c - pthread比 “default”版本慢

标签 c multithreading pthreads

情况
我想看看使用pthread的优势。如果我没有记错的话:线程允许我并行执行程序的给定部分。
所以这是我要完成的任务:我想制作一个程序,该程序接受一个数字(假设为n)并输出[0..n]的总和。
代码

#define MAX 1000000000

int
main() {
    long long n = 0;
    for (long long i = 1; i < MAX; ++i)
        n += i;

    printf("\nn: %lld\n", n);
    return 0;
}

time: 0m2.723s


据我了解,我可以简单地将这个数字MAX除以2并让2 threads做这份工作。
代码
#define MAX          1000000000
#define MAX_THREADS  2
#define STRIDE       MAX / MAX_THREADS

typedef struct {
    long long off;
    long long res;
} arg_t;

void*
callback(void *args) {
    arg_t *arg = (arg_t*)args;

    for (long long i = arg->off; i < arg->off + STRIDE; ++i)
        arg->res += i;

    pthread_exit(0);
}

int
main() {
    pthread_t threads[MAX_THREADS];
    arg_t     results[MAX_THREADS];

    for (int i = 0; i < MAX_THREADS; ++i) {
        results[i].off = i * STRIDE;
        results[i].res = 0;

        pthread_create(&threads[i], NULL, callback, (void*)&results[i]);
    }

    for (int i = 0; i < MAX_THREADS; ++i)
        pthread_join(threads[i], NULL);

    long long result;
    result = results[0].res;

    for (int i = 1; i < MAX_THREADS; ++i)
        result += results[i].res;

    printf("\nn: %lld\n", result);

    return 0;
}

time: 0m8.530s


问题
带有pthread的版本运行速度较慢。从逻辑上讲,此版本应运行得更快,但创建线程可能会更昂贵。
有人可以提出解决方案或在这里显示我在做什么/理解错误吗?

最佳答案

您的问题是缓存崩溃并缺乏优化(我敢打赌,如果不进行优化,您正在编译)。
的原始(-O0)代码

for (long long i = arg->off; i < arg->off + STRIDE; ++i)
    arg->res += i;
将访问*arg的内存。按照您的方式定义results数组,该内存非常接近下一个arg的内存,并且两个线程将争夺同一条缓存行,从而使RAM缓存非常无效。
如果使用-O1进行编译,则循环应改为使用寄存器,并且仅在末尾写入内存。然后,您应该使用线程获得更好的性能(gcc上更高的优化级别似乎可以完全优化循环)
另一个(更好)的选择是在缓存行上对齐arg_t:
typedef struct {
    _Alignas(64) /*typical cache line size*/ long long off;
    long long res;
} arg_t;
然后,无论是否启用优化,您都应该在线程上获得更好的性能。
通常,良好的缓存利用率在多线程编程中非常重要(而Ulrich Drepper在他臭名昭著的What Every Programmer Should Know About Memory中对此话题有很多话要说)。

关于c - pthread比 “default”版本慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63886802/

相关文章:

c - 将文件范围变量放入结构中?有什么好处

c++ - 使用 pthread 时出现多个参数(带结构)错误

pthreads - sleep 表现

c++ - _dopr 是什么意思

c - 参数传递如何工作?

iphone:如何像 NSCalendar 一样混合枚举

.net - 如何在 Visual Studio 中只调试一个线程

java - SwingWorker 和 Executor 的区别

linux - 如果两个核心试图同时写入主存中的同一个地方会发生什么?

c++ - 线程可以在对内核的系统调用中被抢占吗?