多线程中的虚假共享

问题描述 投票:0回答:1

下面的代码在我增加了 NTHREADS. 为什么使用更多的线程会使程序运行更慢?有什么办法可以解决吗?有人说这是关于 虚与委蛇 但我不太明白这个概念。

程序的基本功能是计算从1到1亿的总和,而使用多线程的想法是把数字列表分成几个块,然后并行计算每个块的总和,以使计算更快。使用多线程的想法是将数字列表分成几个块,然后并行计算每个块的总和,以使计算更快。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define LENGTH 100000000
#define NTHREADS 2
#define NREPEATS 10
#define CHUNCK (LENGTH / NTHREADS)

typedef struct {
        size_t id;
        long *array;
        long result;
} worker_args;

void *worker(void *args) {

        worker_args *wargs = (worker_args*) args;

        const size_t start = wargs->id * CHUNCK;
        const size_t end = wargs->id == NTHREADS - 1 ? LENGTH : (wargs->id+1) * CHUNCK;

        for (size_t i = start; i < end; ++i) {
                wargs->result += wargs->array[i];
        }

        return NULL;
}

int main(void) {

        long* numbers = malloc(sizeof(long) * LENGTH);
        for (size_t i = 0; i < LENGTH; ++i) {
                numbers[i] = i + 1;
        }

        worker_args *args = malloc(sizeof(worker_args) * NTHREADS);

            for (size_t i = 0; i < NTHREADS; ++i) {
                    args[i] = (worker_args) {
                            .id = i,
                            .array = numbers, 
                            .result = 0
                    };
            }

            pthread_t thread_ids[NTHREADS];

            for (size_t i = 0; i < NTHREADS; ++i) {
                    pthread_create(thread_ids+i, NULL, worker, args+i);
            }

            for (size_t i = 0; i < NTHREADS; ++i) {
                    pthread_join(thread_ids[i], NULL);
            }

            long sum = 0;

            for (size_t i = 0; i < NTHREADS; ++i) {
                sum += args[i].result;
            }

            printf("Run %2zu: total sum is %ld\n", n, sum);

        free(args);
        free(numbers);
}

c multithreading pthreads
1个回答
4
投票

为什么使用更多的线程会使程序运行得更慢?

创建和加入线程是有开销的。如果线程没有太多的事情要做,那么这个开销可能比实际工作更贵。

你的线程只是在做一个简单的和,这并不昂贵。同时考虑到从例如10个线程到11个线程并不会对每个线程的工作负载有很大的改变。

10个线程-->每个线程10000000个总和

11个线程-> 9090909每个线程的总和。

创建一个额外线程的开销可能会超过每个线程 "节省的工作负荷"。

在我的电脑上,程序运行时间不到100毫秒。多线程是不值得的。

在多线程值得做之前,你需要一个更密集的处理任务。

另外,请注意,创建比你的计算机所拥有的核心数(包括超线程)更多的线程很少有意义。

虚假分享

是的,"虚假共享 "会影响多线程程序的性能,但我怀疑这是不是你的案例中的真正问题。

"虚假共享 "是在(某些)缓存系统中发生的事情,当两个线程(或者说是两个核心)向属于同一缓存行的两个不同的变量写入时。在这种情况下,两个线程争夺缓存线的所有权(用于写入),因此,他们必须一次又一次地刷新内存和缓存。这对性能很不利。

正如我所说的--我怀疑那是你的问题。一个聪明的编译器会只使用CPU寄存器来完成你的循环,并且只在最后向内存写入。你可以检查你的代码的反汇编,看看是否是这样。

你可以通过增加结构体的sizeof来避免 "虚假共享",使每个结构体都适合你的系统中的一个缓存行的大小。

© www.soinside.com 2019 - 2024. All rights reserved.