【问题标题】:Will there be serious performance degradation when using multiple threads to write to memory concurrently on Linux?在 Linux 上使用多个线程并发写入内存时会不会出现严重的性能下降?
【发布时间】:2021-06-12 12:49:23
【问题描述】:

我今天写了一个多线程。线程的任务是将数据写入一个大数组。单线程耗时0.7s左右,但两个线程独立并发写需要20多秒。同样的操作在Windows下或者Linux下多进程秒都是0.7s左右。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/types.h>

#define SIZE_IN_MB 256
#define NUM_BYTE (SIZE_IN_MB*1024*1024)
#define NUM_LONG (NUM_BYTE/sizeof(long))

#define CHILD_COUNT 2
#define STEP_SIZE   1  //use to avoid cache,when set to 8

unsigned long Time[CHILD_COUNT];

struct Arg {
    unsigned long *data;
    int index;
};

unsigned long diffTime(struct timeval *end, struct timeval *start) {
    return labs((end->tv_sec - start->tv_sec) * 1000 + (end->tv_usec - start->tv_usec) / 1000);
}

void getTime(struct timeval *t) {
    gettimeofday(t, NULL);
}

unsigned long writeData() {
    struct timeval start, end;
    getTime(&start);
    unsigned long *data = (unsigned long *) malloc(NUM_LONG * sizeof(long));
    for (int i = 0; i < STEP_SIZE; ++i) {
        for (size_t k = i; k < NUM_LONG; k+=STEP_SIZE)
            data[k] = 0x5a5a5a5a5a5a5a5a + rand();
    }
    getTime(&end);
    free(data);
    return diffTime(&end, &start);
}

void *child(void *arg) {
    Time[((struct Arg *) arg)->index] = writeData();
}

void waitAll(pthread_t threads[]) {
    for (int i = 0; i < CHILD_COUNT; i++) {
        pthread_join(threads[i], NULL);
    }
}

void printAverTime(int count) {
    unsigned long time = 0;
    for (int i = 0; i < count; ++i) {
        time += Time[i];
    }
    printf("Thread: %ld\n", time / count);
}

void thread_test() {
    pthread_t threads[CHILD_COUNT];
    struct Arg arg[CHILD_COUNT] = {};
    for (int i = 0; i < CHILD_COUNT; i++) {
        arg[i].index = i;
        pthread_create(&threads[i], NULL, child, (void *) &arg[i]);
    }
    waitAll(threads);
    printAverTime(CHILD_COUNT);
}

void process_test() {
    int p[CHILD_COUNT][2];
    for (int i = 0; i < CHILD_COUNT; ++i) {
        pipe(p[i]);
    }
    for (int i = 0; i < CHILD_COUNT; i++) {
        if (fork() == 0) {
            unsigned long t = writeData();
            write(p[i][1], &t, sizeof(t));
            exit(0);
        }
    }
    unsigned long t = 0,tmp= 0;
    for (int i = 0; i < CHILD_COUNT; ++i) {
        read(p[i][0], &tmp, sizeof(tmp));
        t += tmp;
    }
    printf("Process: %ld\n", t / CHILD_COUNT);
}

int main() {
    thread_test();
    process_test();
}

【问题讨论】:

    标签: c linux multithreading memory


    【解决方案1】:

    您在使用多线程时付出的代价不是写入内存,而是您调用 rand() 的事实,这涉及锁定,在以下嵌套循环中多次 writeData():

    for (int i = 0; i < STEP_SIZE; ++i) {
        for (size_t k = i; k < NUM_LONG; k+=STEP_SIZE)
            data[k] = 0x5a5a5a5a5a5a5a5a + rand();
    }
    

    因此,您将承受巨大的损失,因为每次调用 rand() 一次只能有一个线程进入,而所有其他线程都必须等待,而且这种等待会产生开销。

    您可以通过使用 rand() 的可重入形式(例如 rand_r()(记录在 @ 987654321@)

    unsigned int seed = rand();
    for (int i = 0; i < STEP_SIZE; ++i) {
        for (size_t k = i; k < NUM_LONG; k+=STEP_SIZE)
            data[k] = 0x5a5a5a5a5a5a5a5a + rand_r(&seed);
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-19
      • 2019-03-06
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      • 2013-05-25
      • 2017-03-03
      • 1970-01-01
      相关资源
      最近更新 更多