为什么我的多线程程序比单线程程序慢?

Why my multi thread program is slower than single thread program?

我知道很多人已经问过这个话题了,但我真的不明白为什么我的程序即使不计算标准输入和输出也很慢。

这是我的单线程程序。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LEN 30000
int **arr;

int main()
{
    arr = malloc(sizeof(int *) * LEN);
    for(int i=0;i<LEN;i++)
        arr[i] = malloc(sizeof(int) * LEN);
    clock_t st, ed;
    st = clock();
    for(int i=0;i<LEN;i++)
        for(int j=0;j<LEN;j++)
            arr[i][j] = 1;
    ed = clock();
    printf("time : %ld\n", ed-st);
}

这是我的多线程程序

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#define LEN 30000
int **arr;

void *thread_excute(void *thread_argv)
{
    int start = ((int *)thread_argv)[0];
    int height = ((int *)thread_argv)[1];
    for(int i=0;i<height;i++)
        for(int j=0;j<LEN;j++)
            arr[start+i][j] = 1;
    return 0;
}

int main()
{
    arr = malloc(sizeof(int *) * LEN);
    for(int i=0;i<LEN;i++)
        arr[i] = malloc(sizeof(int) * LEN);
    clock_t st, ed;
    st = clock();
    // thread = 4
    pthread_t *thread_num = malloc(sizeof(int) * 4);
    int **argv = malloc(sizeof(int *) * 4);
    for(int t=0;t<4;t++)
    {
        argv[t] = malloc(sizeof(int) * 2);
        argv[t][0] = t*(LEN/4);
        argv[t][1] = LEN/4;
        pthread_create(&thread_num[t], 0, thread_excute, (void *)argv[t]);
    }
    for(int t=0;t<4;t++)
        pthread_join(thread_num[t], 0);
    ed = clock();
    printf("time : %ld\n", ed-st);
}

这是将 30000 * 30000 int 数组填充为 1 的程序。 我制作多线程程序,每个线程填充不同的数组行。 所以我猜想多线程程序会比单线程程序快。 但这是输出。

// single thread program
time : 3782958
// multi thread program
time : 3997991

我 运行 这个程序在 Ubuntu 20.04 上,我有 4 个 cpu 核心。 我通过 gcc file.c -o file -lpthread

编译这段代码

我不知道为什么会这样。

这是您的 multi-thread 程序的调整版本:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LEN 30000
int **arr;

void *thread_excute(void *thread_argv) {
    // clock_t st, ed;
    // st = clock();
    int start = ((int *)thread_argv)[0];
    int height = ((int *)thread_argv)[1];
    int thread = ((int *)thread_argv)[2];
    for(int i=start; i<start+height; i++)
        for(int j=0;j<LEN; j++)
            arr[i][j] = 1;
    // ed = clock();
    // printf("%d %ld %ld %ld\n", thread, st, ed, ed-st);
    return 0;
}

int main(int argc, char *argv[]) {
    arr = calloc(1, sizeof(int *) * LEN);
    arr[0] = calloc(LEN, sizeof(int) * LEN);
    for(int i=1; i<LEN; i++)
        arr[i] = arr[0] + i * LEN;
    clock_t st, ed;
    unsigned threads = (argc == 2) ? atoi(argv[1]) : 4;
    pthread_t *thread_num = malloc(sizeof(int) * threads);
    st = clock();
    int **argv2 = malloc(sizeof(int *) * threads);
    for(int t=0; t<threads; t++) {
        argv2[t] = malloc(sizeof(int) * 3);
        argv2[t][0] = t * (LEN/threads);
        argv2[t][1] = LEN/threads;
        argv2[t][2] = t;
        pthread_create(&thread_num[t], 0, thread_excute, (void *)argv2[t]);
    }
    for(int t=0; t<threads; t++)
        pthread_join(thread_num[t], 0);
    ed = clock();
    printf("%ld\n", ed-st);
}

如果您使用 -O3 构建它并使用 (bash) 时间进行基准测试,我将无法再可靠地获得比单一版本更低的 multi-threaded 运行线程版本(4 核,8 超线程):

threads clock time (real) time (sys)
single 352917 0m0.361s 0m0.089s
multi 1 365564 0m0.373s 0m0.273s
multi 2 524756 0m0.274s 0m0.430s
multi 4 774477 0m0.215s 0m0.589s
multi 8 1711224 0m0.331s 0m1.136s

我的结论是 clock() 不是衡量“慢”的好指标。在我们从 4 线程变为 8 线程之前,您的程序会越来越快(这台笔记本电脑有 4 个内核/8 个超线程)。另一个要点是,随着线程数量的增加,操作系统会做更多的工作来完成同样的事情。