将工作分配给更多线程需要更多时间,为什么?

2024-04-10

我有一个小的 C 程序可以计算pi用一个蒙特卡洛 http://en.wikipedia.org/wiki/Monte_Carlo_method#Introduction-模拟基本上只是测试随机点 [x,y] 是否在圆内部或外部。

近似pi我必须使用大量样本n其复杂度成正比O(n)。所以试图计算大量的样本n,我实现了POSIX 线程 http://en.wikipedia.org/wiki/POSIX_Threadsapi 来并行化计算能力。

我的代码如下所示:

pthread_t worker[nthreads]; /* creates workers for each thread */
struct param aparam[nthreads]; /* struct param{ long* hits; long rounds; }; */
long nrounds = nsamples / nthreads; /* divide samples to subsets of equal rounds per thread */

for (int i = 0; i < nthreads; ++i) { /* loop to create threads */
    aparam[i].hits = 0;
    aparam[i].rounds = nrounds;
    pthread_create(&worker[i], NULL, calc_pi, &aparam[i]); /* calls calc_pi(void* vparam){}  */ 
}

long nhits = 0;
for (int j = 0; j < nthreads; ++j) { /* collects results */
    pthread_join(worker[j], NULL);
    nhits += (long)aparam[j].hits; /* counts hits inside the cicrle */
}

这就是每个线程正在做的事情:

void* calc_pi(void* vparam)
{ /* counts hits inside a circle */
    struct param *iparam;
    iparam = (struct param *) vparam;
    long hits = 0;
    float x, y, z;
    for (long i = 0; i < iparam->rounds; ++i) {
        x = (float)rand()/RAND_MAX;
        y = (float)rand()/RAND_MAX;
        z = x * x + y * y;
        if (z <= 1.f) /* circle radius of 1 */
            ++hits;
    }
    iparam->hits = (long*)hits;
    return NULL;
}

现在我有一个奇怪的观察。使用同一组样本n并且随着线程数量的增加i这个程序需要更多的时间而不是更少的时间.

以下是一些平均运行时间(可重现):

-------------------------------------------------
| Threads[1] | Samples[1] | Rounds[1] | Time[s] |
-------------------------------------------------
|        32  |  268435456 |   8388608 |    118  |
|        16  |  268435456 |  16777216 |    106  |
|         8  |  268435456 |  33554432 |    125  |
|         4  |  268435456 |  67108864 |    152  |
|         2  |  268435456 | 134217728 |     36  |
|         1  |  268435456 | 268435456 |     15  |
-------------------------------------------------

例如,为什么两个线程执行相同的工作所花费的时间是单个线程的两倍以上?我的假设是两个线程划分工作应该减少至少 50% 的时间。

使用 GCC 4.9.1 和以下标志编译:

gcc -O2 -std=gnu11 -pthread pipa.c -lpthread -o pipa

我的硬件是双 Intel Xeon E5520(2 个处理器,每个 4 核)@ 2.26 GHz,禁用超线程,运行具有 2.6.18 内核的 Scientific Linux。

有任何想法吗?


线程执行的最昂贵的操作是调用rand(). The rand()是一个简单、简单且通常不可 MT 可扩展的函数(因为它保证相同的种子产生相同的序列random数字)。我认为里面的锁rand()正在序列化所有线程。(*)

确认是否是问题的一个简单技巧是在调试器下启动程序,然后多次:暂停它,捕获线程的堆栈跟踪,然后继续。无论堆栈跟踪中最常出现什么,很可能就是瓶颈。

(*) 使它变得更慢的原因是锁争用会导致额外的性能损失。此外,许多线程增加了进程调度和上下文切换的额外开销。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将工作分配给更多线程需要更多时间,为什么? 的相关文章

  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 平滑滚动.net 表单

    您好 我正在 net 中使用表单 并且在运行时动态添加大量链接标签 我将这些链接标签添加到面板并将该面板添加到 winform 当链接标签的数量增加时 表单会显示一个自动滚动条 垂直 现在 当我使用自动滚动向下滚动时 表单在滚动时不会更新其
  • 类特定的新删除运算符是否必须声明为静态

    标准中是否要求类特定的 new new delete 和 delete 是静态的 我可以让它们成为非静态成员运算符吗 为什么需要它们是静态的 它们被隐式声明为静态 即使您没有键入 static
  • 找不到 assimp-vc140-mt.dll ASSIMP

    我已经从以下位置下载了 Assimp 项目http assimp sourceforge net main downloads html http assimp sourceforge net main downloads html Ass
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • 如何在 C# 控制台应用程序中将修饰符(ctrl、alt、shift)按键捕获为单个按键?

    Console ReadKey 仅在按下 正常 键时捕获输入 然后将修饰符 如果有 附加为键信息的一部分 如何将单个修饰键注册为输入 提供了一种解决方案这个链接 https blogs msdn microsoft com toub 200
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • Android 为什么这不会抛出错误的线程异常?

    我的印象是视图只能从主线程操作 但是 为什么这不会崩溃 public class MainActivity extends Activity TextView tv Override protected void onCreate Bund
  • 在 JSQMessagesViewController 中显示 LocationMediaItem

    我刚刚尝试实施LocationMediaItem in my Xamarin iOS应用程序使用JSQMessagesViewController 一切都很顺利 唯一的问题是UICollectionView应该显示位置的单元格永远停留在加载
  • 从 WebBrowser 控件 C# 获取滚动值

    我试图在 WebBrowser 控件中获取网页的 Y 滚动索引 但无法访问内置滚动条的值 有任何想法吗 对于标准模式下的 IE 使用文档类型 正如你所说 scrollTop是的财产元素 而不是 HtmlDocument htmlDoc th
  • 如何在服务器端按钮点击时关闭当前标签页?

    我尝试在确认后关闭当前选项卡 因此我将以下代码放在确认按钮的末尾 但选项卡没有关闭 string jScript ClientScript RegisterClientScriptBlock this GetType keyClientBl
  • 将二进制数据从 C# 上传到 PHP

    我想将文件从 Windows C 应用程序上传到运行 PHP 的 Web 服务器 我知道 WebClient UploadFile 方法 但我希望能够分块上传文件 以便我可以监控进度并能够暂停 恢复 因此 我正在读取文件的一部分并使用 We
  • 运行选定的代码生成器时出错:“未将对象引用设置到对象的实例。”错误?

    我已经尝试了所有解决方案 例如修复 VS 2013 但没有用 当您通过右键单击控制器文件夹来创建控制器并添加控制器时 然后右键单击新创建的控制器的操作并选择添加视图 当我尝试创建视图时 就会发生这种情况 它不是一个新项目 而是一个现有项目
  • 将标量添加到特征矩阵(向量)

    我刚刚开始使用 Eigen 库 无法理解如何向所有矩阵成员添加标量值 假设我有一个矩阵 Eigen Matrix3Xf mtx Eigen Matrix3Xf Ones 3 4 mtx mtx 1 main cxx 104 13 error
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 了解使用 Windows 本机 WPF 客户端进行 ADFS 登录

    我已经阅读了大量有关 ADFS 与 NodeJS Angular 或其他前端 Web 框架集成以及一般流程如何工作的文献 并通过 Auth0 Angular 起始代码构建了概念证明 但我不明白如何这可以与本机 WPF Windows 应用程
  • 抛出 Java 异常时是否会生成堆栈跟踪?

    这是假设我们不调用 printstacktrace 方法 只是抛出和捕获 我们正在考虑这样做是为了解决一些性能瓶颈 不 堆栈跟踪是在构造异常对象时生成的 而不是在抛出异常对象时生成的 Throwable 构造函数调用 fillInStack
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行

随机推荐