繁体   English   中英

多线程效率

[英]efficiency in multithreading

假设我有这样的代码

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个<i_max线程的信号量。

谢谢,

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

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

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

顺便说一句-如果您使用的是Visual C ++,则Visual C ++ v10中有一个有趣的新并发运行时 ,正是针对这种类型的问题。 这有点类似于.Net Framework 4中添加的任务并行库,以简化多核/多CPU代码的实现。

避免创建线程,除非您可以让它们忙!

如果您的方案是受计算限制的,则应将产生的线程数减至希望代码在其上运行的核心数。 如果创建的线程多于内核,则OS必须浪费时间和资源来调度线程在可用内核上执行。

如果您的方案是IO受限的,那么您应该考虑使用排队的异步IO操作,并在返回异步结果后检查响应代码。 同样,在这种情况下,每个IO操作产生一个线程是非常浪费的,因为这将导致OS必须浪费时间来调度已停止的线程。

这里的每个人基本上都是正确的,但是这是分散工作并使所有处理器保持繁忙的快捷方法。 当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(线程构建基块)可以很好地将其抽象出来,并让您进入想要做的实际工作。

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

threads are created. 如果并行化内部循环而不是外部循环,那么将为外部循环的每次迭代创建线程。 more than if you parallelized the outer loop instead. 与并行循环相比, 的阶更大。

也就是说,最佳并行化取决于您的实际问题。 因此,实际上可以并行化内部循环。

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

您仍然有时间将数据加载到卡上进行考虑。

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

并行化(破坏线程)是昂贵的。 请记住,您需要设置n个线程,然后再同步n个线程。 这代表了例程运行时间以外的成本c,例程本身本身可以使并行处理的总时间大于单线程模式。 这取决于所讨论的问题。 通常,存在一个临界大小,超过该大小并行速度会更快。

我建议在第一个for循环中进入并行区域会更快。 如果在内部循环上执行此操作,则每次循环运行时都必须派生/加入,这会增加代码速度。 理想情况下,您只希望创建一次线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM