多线程的效率

时间:2010-12-13 20:02:47

标签: c++ multithreading performance simulation

假设我有这样的代码

for(i = 0; i < i_max; i++)
  for(j = 0; j < j_max; j++)
     // do something

我希望通过使用不同的线程来做到这一点(假设//执行某些任务彼此独立,例如考虑montecarlo模拟)。我的问题是:为每个i值创建一个线程,比为每个j值创建一个线程更好吗?像这样的东西

for(i = 0; i < i_max; i++)
  create_thread(j_max);

另外:合适数量的线程是什么?我应该创建i_max线程,或者使用k <1的信号量。 i_max线程在任何给定时间并发运行。

谢谢,

5 个答案:

答案 0 :(得分:4)

分配工作负载的最佳方法是依赖于工作负载。

广义 - 对于可并行化的工作负载,请使用OpenMP;对于异构工作负载,请使用线程池。如果可以,请避免管理自己的线程。

蒙特卡罗模拟应该是真正的并行代码而不是线程池的理想选择。

顺便说一句 - 如果你使用的是Visual C ++,那么在Visual C ++ v10中就会出现一个有趣的新Concurrency Runtime来解决这类问题。这有点类似于添加到.Net Framework 4中的任务并行库,以简化多核/多CPU代码的实现。

答案 1 :(得分:2)

避免创建线程,除非你能让它们忙碌!

如果您的方案受计算限制,那么您应该将生成的线程数量减少到您希望代码运行的内核数量。如果您创建的线程数多于核心数,则操作系统必须浪费时间和资源来安排线程在可用内核上执行。

如果您的方案是IO绑定的,那么您应该考虑使用排队的异步IO操作,并在返回异步结果后检查响应代码。同样,在这种情况下,每个IO操作产生一个线程是非常浪费的,因为你将导致操作系统不得不浪费时间来安排停滞的线程。

答案 2 :(得分:2)

这里的每个人基本上都是正确的,但是这是一种分解工作并保持所有处理器忙碌的快捷方式。当1)创建线程与迭代中完成的工作相比昂贵时,这种方法效果最好2)大多数迭代需要大约相同的时间才能完成

首先,为每个处理器/核心创建1个线程。这些是你的工作线程。他们闲着,直到他们被要求做某事。

现在,将您的工作分开,以便同时需要的数据工作紧密相连。我的意思是,如果你在一台双处理器机器上处理一个十元素阵列,你将它拆分,以便一组是元素1,2,3,4,5而另一组是6,7 ,8,9,10。您可能想要将其分解为1,3,5,7,9和2,4,6,8,10,但随后您将导致更多的错误共享(http://en.wikipedia.org/你的缓存中的wiki / False_sharing。

现在,每个处理器都有一个线程,每个线程都有一组数据,您只需告诉每个线程处理一组独立的数据。

所以在你的情况下,我会做这样的事情。

for (int t=0;t<n_processors;++t)
{
  thread[t]=create_thread();
  datamin[t]=t*(i_max/n_processors);
  datamax[t]=(t+1)*(i_max/n_processors);
}

for (int t=0;t<n_processors;++t)
  do_work(thread[t], datamin[t], datamax[t], j_max)

//wait for all threads to be done

//continue with rest of the program.

当然,我遗漏了处理数据的事情,而不是处理器数量的整数倍,但这些很容易修复。

此外,如果您对第三方库不感兴趣,英特尔的TBB(线程构建模块)可以很好地从您那里抽象出来并让您完成您想要做的实际工作。

答案 3 :(得分:1)

创建和调用线程的所有内容都相对昂贵,因此您希望尽可能少地执行此操作。

如果并行化内部循环而不是外部循环,那么对于外部循环的每次迭代,都会创建 j_max 个线程。 i_max 的顺序比你并行化外环更多。

那就是说,最好的并行化取决于你的实际问题。根据这一点,实际上并行化内部循环是有意义的。

答案 4 :(得分:0)

取决于您将要模拟的任务和平台。例如,在CUDA的架构上,您可以将任务分开,以便每个i,j,1单独完成。

您仍有时间将数据加载到卡上以供考虑。

使用for循环和类似OpenMP / MPI /您自己的线程机制,您基本上可以选择。在一种情况下,并行线程被分解,并且j在每个线程上顺序循环。在ohter中,顺序处理循环,并在每次并行化中分解循环。

并行化(打破线程)成本很高。请记住,您需要设置n个线程,然后同步n个线程。这表示在例程的运行时间之上的成本c,其本身可以使并行处理的总时间比单线程模式的总时间更长。这取决于有问题的问题;通常,有一个临界尺寸超过平行速度更快。

我建议在第一个for循环中突破并行区域会更快。如果在内部循环中执行此操作,则每次循环运行时都必须进行fork / join,这会增加代码速度的大量开销。理想情况下,您只需要创建一次线程。