【问题标题】:tasks run in thread takes longer than in serial?在线程中运行的任务比在串行中运行的时间更长?
【发布时间】:2015-10-30 15:17:42
【问题描述】:

所以我在 400 万个节点上做一些计算。

非常酷的串行版本只有一个 for 循环,循环 400 万次并进行 400 万次计算。这大约需要 1.2 秒。

当我将 for 循环拆分为 4 个 for 循环并且每个循环执行 1/4 的计算时,总时间变为 1.9 秒。

我猜在创建 for 循环时会有一些开销,并且可能与 cpu 喜欢以块计算数据有关。

真正困扰我的是,当我尝试在 8 核机器上将 4 个循环放到 4 个线程上时,每个线程需要 0.9 秒才能完成。 我希望他们每个人只需要 1.9/4 秒。

我不认为有任何竞争条件或同步问题,因为我所做的只是有一个 for 循环来创建 4 个线程,这需要 200 微秒。然后一个 for 循环将它们连接起来。

计算从共享数组读取并写入不同的共享数组。 我确信他们没有写入同一个字节。

开销从何而来?

main: ncores: 核心数。 node_size:图的大小(400万节点)

        for(i = 0 ; i < ncores ; i++){
            int *t = (int*)malloc(sizeof(int));
            *t = i;
            int iret = pthread_create( &thread[i], NULL, calculate_rank_p, (void*)(t));

        }
        for (i = 0; i < ncores; i++)
        {
            pthread_join(thread[i], NULL);
        }

calculate_rank_p:vector为页面排名计算的排名向量

Void *calculate_rank_pthread(void *argument) {
    int index = *(int*)argument;
    for(i = index; i < node_size ; i+=ncores)     
       current_vector[i] = calc_r(i, vector);
    return NULL;     
}

calc_r:这只是使用压缩行格式的页面排名计算。

double calc_r(int i, double *vector){
    double prank = 0;
    int j;
    for(j = row_ptr[i]; j < row_ptr[i+1]; j++){
        prank += vector[col_ind[j]] * val[j];
    }
    return prank;
}

所有未声明的都是全局变量

【问题讨论】:

  • 贴出代码,让我们看看问题出在哪里。
  • 解决此问题所需的时间比某些代码发布的时间要长。因此,通过一次性(并行)发布所有需要的代码、输入和预期输出),这可以快速推进,而不是连续要求各种信息。
  • Ohwait.. 'for(i = index; i
  • 你应该给每个线程一个连续的整数块来处理,'i++',而不是'i+=ncores'。
  • ncores 是核心数(线程)。就我而言,4.

标签: c parallel-processing pthreads


【解决方案1】:

计算从共享数组读取并写入不同的共享数组。我确信他们没有写入同一个字节。

如果不查看相关代码并了解更多详细信息,就无法确定,但这听起来可能是由于虚假共享,或者......

错误共享的性能问题(也称为缓存行乒乓),其中线程使用不同的对象,但这些对象恰好在内存中足够接近,以至于它们落在同一缓存行上,并且缓存系统将它们视为由硬件写锁有效保护的单个块,一次只能持有一个内核。这会导致真实但无形的性能竞争;无论哪个线程当前拥有独占所有权,以便它可以对缓存行进行物理更新,都会默默地限制尝试使用位于同一行的不同(但是,唉,附近)数据的其他线程。

http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206

更新

这看起来很可能触发错误共享,具体取决于向量的大小(尽管帖子中仍然没有足够的信息可以确定,因为我们看不到各种 vector 是如何分配的.

for(i = index; i < node_size ; i+=ncores) 

i += ncores 不是交错处理哪个核心处理哪些数据,而是为每个核心提供一个处理数据范围。

【讨论】:

  • 为避免这种情况,我是否应该将线程的结果存储在单独的数组中,然后在完成后将它们组合在一起?
  • 它们不一定是单独的数组,但线程需要在足够分离的内存区域上工作,这样它们就不会争用相同的缓存行。链接的文章提供了一些非常好的建议。但是,如果这是您的问题,它肯定会解决问题,每个线程使用一个数组,因为这会强制每个线程有自己的地址范围。
  • 所以我只是尝试在每个线程中创建一个局部变量并将计算结果保存在那里。但是,每个线程的计算时间并没有改善。我只使用 gettimeofday 计算计算时间。
  • 是的 - 这看起来太虚假分享了,应该因为蔑视或欺诈而入狱:)
  • @LoveProgramming:见更新。您发布的代码中存在触发虚假共享的候选。
猜你喜欢
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2016-10-07
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 2013-07-08
  • 2014-09-10
相关资源
最近更新 更多