【问题标题】:Increasing pthreads thread count has no effect on speed增加 pthreads 线程数对速度没有影响
【发布时间】:2013-10-27 10:12:06
【问题描述】:

在下面的程序中,增加线程数根本不会产生任何加速好处(在 linux 下用 time 命令测量)。我在以下处理器上运行过它:

  • 英特尔 i5 M520
  • 英特尔至强 X5650

在我看来,在线程之间划分工作的逻辑是正确的。我什至尝试移除锁,这显然给出了错误的结果,但仍然没有提高速度。有什么想法吗?

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

double sum;
pthread_mutex_t mutex;
typedef struct {
    int start;
    int end;
}sumArg;

void *sumRoots(void *arg) {
    sumArg s = *((sumArg *) arg);
    int i = s.start;
    double tmp;
    while(i <= s.end) {
        tmp = sqrt(i);
        pthread_mutex_lock(&mutex);
        sum += tmp;
        pthread_mutex_unlock(&mutex);
        i++;
    }
    free(arg);
}

int main(int argc, char const *argv[]) {
    int threadCount = atoi(argv[1]);
    int N = atoi(argv[2]);
    if (N < 1 || threadCount < 1) printf("Usage: ./sumOfRoots threads N\n");

    pthread_t tid[threadCount];
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_mutex_init(&mutex, NULL);

    sumArg *s;
    int i = 0;
    while(i < threadCount) {
        s = (sumArg *) malloc(sizeof(sumArg));
        s->start = ((N/threadCount) * i) + 1;
        s->end = (N/threadCount) * (i + 1);
        pthread_create(&tid[i], &attr, sumRoots, s);
        i++;
    }

    i = 0;
    while(i < threadCount) pthread_join(tid[i++], NULL);
    printf("sum: %f\n", sum);
    return 0;
}

编辑: 以下是该程序的一些运行,均在 i5 M520 上运行:

time ./sumOfRoots 1 1000000000
sum: 21081851083600.558594

real    0m21.933s
user    0m21.268s
sys     0m0.000s

time ./sumOfRoots 2 1000000000
sum: 21081851083600.691406

real    0m21.207s
user    0m21.020s
sys     0m0.008s

time ./sumOfRoots 4 1000000000
sum: 21081851083600.863281

real    0m21.488s
user    0m21.116s
sys     0m0.016s

time ./sumOfRoots 8 1000000000
sum: 21081851083601.777344

real    0m21.432s
user    0m21.092s
sys     0m0.020s

我认为总和的变化是由浮点精度损失引起的。

【问题讨论】:

  • 你传递了什么参数?
  • 您将 numthreads 设置为什么值?
  • 但是,请注意,像这样在内部循环中锁定共享变量会导致性能下降。
  • 我认为绝对没有理由拥有该互斥锁。计算局部循环运行的局部和,然后在循环之后锁存互斥锁一次,以将局部子添加到累积的sum 全局中。如所写,您花费了 难以置信 的时间来锁定一个解锁互斥锁,除了设计选择之外没有任何真正的原因。而且,您投入的线程越多,您要引入的互斥锁的争用就越多。
  • 不只是互斥量被争用,还有变量sum 本身(缓存行争用)。

标签: c multithreading pthreads


【解决方案1】:

时间几乎保持不变的原因是它以同步为主。在我的电脑上,单线程解决方案更快!

如下更改代码使时序符合预期:

void *sumRoots(void *arg) {
    sumArg s = *((sumArg *) arg);
    int i = s.start;
    double tmp = 0;
    while(i <= s.end) {
        tmp += sqrt(i++);
    }
    pthread_mutex_lock(&mutex);
    sum += tmp;
    pthread_mutex_unlock(&mutex);
    free(arg);
    return 0;
}

现在你的线程运行了一段时间没有同步,然后在添加过程中只同步一次。

我在系统上看到的时间如下:

> time ./a.out 1 1000000000
sum: 21081851083600.558594
real    0m13.220s
user    0m13.098s
sys 0m0.009s

> time ./a.out 2 1000000000
sum: 21081851083600.863281

real    0m6.613s
user    0m12.930s
sys 0m0.027s

【讨论】:

  • 我打算提出同样的建议,甚至让每个线程返回一个单独的总和。如果您以“线程创建顺序”对线程汇总值求和,您将最大程度地减少错误(因为在每个线程中求和的值已经单调增加)。 (在实际代码中,您可能想要执行Kahan summation 或类似的操作。)
猜你喜欢
  • 1970-01-01
  • 2020-09-02
  • 2018-12-02
  • 2021-08-16
  • 1970-01-01
  • 2015-11-28
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多