如何告诉多核/多CPU机器并行处理循环中的函数调用?

时间:2020-03-05 18:51:32  来源:igfitidea点击:

我目前正在设计一种应用程序,该应用程序具有一个模块,该模块将从数据库中加载大量数据,并根据情况通过各种计算将其减少到更小的集合。

许多更密集的操作可以确定性地运行,并且可以进行并行处理。

如果我有一个循环,可以循环访问从db传来的大量数据块,并且每次调用一个确定性函数都没有副作用,那么我将如何实现该循环,以便程序不等待函数返回而是设置接下来的通话继续进行,因此可以并行处理?现在,仅凭幼稚的方法来演示该原理就可以了。

我已经读过Google的MapReduce论文,虽然我可以在许多地方使用总体原理,但目前我不会针对大型集群,而将其用于1.0版的单个多核或者多CPU计算机。因此,当前我不确定我是否可以真正使用该库,还是必须自己推出一个精简的基本版本。

我还处于设计过程的早期阶段,到目前为止,我的目标是C语言(对于速度至关重要的位)和Python(对于生产力至关重要的位)作为我的语言。如果有令人信服的原因,我可能会切换,但是到目前为止,我对自己的选择感到满意。

请注意,我知道以下事实:从数据库中检索下一个块比处理当前块要花费更长的时间,然后整个过程将受到I / O约束。但是,我现在暂时假设它不是,并且实际上使用数据库集群或者内存缓存或者其他不受I / O约束的东西。

解决方案

回答

好吧,如果可以选择.net,则他们在并行计算方面付出了很多努力。

回答

我们可以从Google的MapReduce中实现该算法,而无需物理上分开的计算机。只需将每个"机器"视为"线程"即可。线程自动分布在多核计算机上。

回答

如果我们正在使用支持该编译器的编译器,建议我们访问http://www.openmp.org,以一种对代码进行注释的方式
某些循环将并行化。

它的功能也很多,我们可能会发现它很有帮助。

他们的网页报告说,例如gcc4.2将支持openmp。

回答

我可能在这里丢失了一些东西,但是使用pthreads似乎很简单。

设置一个具有N个线程的小型线程池,并使用一个线程来控制所有线程。

主线程只是简单地坐在一个循环中,执行以下操作:

  • 从数据库获取数据块
  • 查找下一个空闲线程如果没有空闲线程,请等待
  • 将块移交给工作线程
  • 返回并从数据库获取下一个块

同时,工作人员线程坐下并执行以下操作:

  • 将自己标记为自由
  • 等待桅杆线程给我大量数据
  • 处理数据块
  • 再次将自己标记为自由

实现此方法的方法可以像两个互斥锁控制的数组一样简单。一个线程具有工作线程(线程池),另一个线程指示每个相应线程是空闲还是忙碌。

根据喜好调整N ...

回答

如果我们仍然计划使用Python,则可能需要看一下Processing。它使用进程而不是线程进行并行计算(由于Python GIL),并提供用于将"工作项"分配到多个进程的类。使用pool类,我们可以编写如下代码:

import processing

def worker(i):
    return i*i
num_workers = 2
pool = processing.Pool(num_workers)
result = pool.imap(worker, range(100000))

这是itertools.imap的并行版本,可将调用分发到进程。我们还可以使用池的apply_async方法并将惰性结果对象存储在列表中:

results = []
for i in range(10000):
    results.append(pool.apply_async(worker, i))

有关更多参考,请参见Pool类的文档。

陷阱:

  • 处理使用fork(),因此在Win32上必须小心
  • 流程之间传递的对象必须是可腌制的
  • 如果工作人员相对较快,则可以调整块大小,即批量发送给工作人员进程的工作项数
  • 池使用后台线程

回答

Java中使用相同的线程池。但是线程池中的线程是可序列化的,并发送到其他计算机并反序列化以运行。

回答

我已经开发了一个MapReduce库,用于在单个服务器上使用多线程/多核。图书馆负责一切,用户只需实施Map and Reduce。它定位为Boost库,但尚未被接受为正式库。查看http://www.craighenderson.co.uk/mapreduce

回答

我们可能对检查libdispatch的代码感兴趣,该代码是Apple的Grand Central Dispatch的开源实现。

回答

英特尔的TBB或者boost :: mpi可能也会引起兴趣。