2011-10-12 36 views
2

我有一个库,其中包含一个IJobMaker实体,该实体创建一定数量的IJob对象,以便在其自己管理的线程上运行。 要跟踪每个IJob的进展情况,我在每个工作中都实施了观察员模式,并使用IProgressObserver。当我想汇报总体进展时,就会遇到困难。多线程任务总体进度报告的设计模式

对我来说,理想的做法是让IProgressOverserver.ReportProgress(float jobProgress, float overallProgress报告工作和整体进度。 IJobMaker可以了解整个工作的每个工作部分,并以某种方式收集每个人的报告。

两个主要的问题出现了:

  1. 同步机制?例如,在IJobMaker内部保留一个互斥体可能会损害性能,因为IProgressOverserver.ReportProgress被调用了很多,互斥体可能会导致上下文切换,而不会导致上下文切换。 InterlockedIncrement看起来是个不错的选择,但由于没有这样的浮点函数,所以我将被迫以整数增量报告进度。 (我想远离C++ 0x功能或Boost)

  2. 设计模式? IJob的进展是从最深的算法中报告的。我需要每一份这样的报告都与中央实体进行沟通,以便总体进度计算,并请拨打IJob中的IProgressObserver.ReportProgress方法。

回答

0

首先,在这种情况下使用浮动是非常糟糕的做法。使用整数。

还有一个建议。您可以使用分段 - 通过一个互斥/原子(一个分段)仅同步几个线程。然后收集所有细分市场。

此外,还有良好的开端环顾四周高度并行算法:http://www.1024cores.net/home/lock-free-algorithms

UDPATE 有例子的问题与浮动

#include <iostream> 
using namespace std; 
int main() { 
    float f = 0; 
    for(int i=0; i<100000-98; ++i) 
    { 
     f += 0.00001; 
    } 
    cout << f << endl; 
} 

所以,如果你有100个就业机会,每个1000步,你会在98之前得到1.0结果,比你想象的要早。

+0

你能详细说明为什么它不好使用浮动?另外,我不确定我是否明白你的分类意思。我如何只同步几个线程? – Leo

+0

花车设计用于各种值。我不认为你在'1E-200' - '1E200'之间有进展。对于你的情况你可以有'AtomicInteger'并做精确的计算,但是我从来没有听说过'AtomicFloat'。是的,你可以将少数几个线段分组。它允许在单个互斥锁上同步更少的线程。 – kan

+0

但我必须同步这些细分才能得到最终答案。也许它会起作用,如果我允许一些'IJob'的进展,直到用户获得整体进展报告为止。然而,既然我想要立即回答,我不得不在分段之间和分段之间进行同步,这似乎同样有害。关于浮点数,我可以有0到1之间的范围。整数也是很宽的范围,但只使用一个子范围。 – Leo

1

一对夫妇对穿线前的建议:

  1. 不报告的每一个进步哪怕一丁点。一旦进行了某个预定义的进度量,或者经过了某个预定义的时间量,或者子作业已经完成,则仅向主线程报告。这可以大大减少同步的数量。
  2. 如果你实现了#1,互斥锁可能工作得很好。
  3. 如果互斥体结果太贵,您可以使用原子整数变量来报告进度:只需将值从“无进度”缩放到“全部完成”到0 ... INT_MAX

就设计API而言,应该不难想出一些合理的东西。我的一般建议是不要过度使用它。

+0

我会尽可能“大致”报告,但我仍然相信使用锁可能会对性能造成不良影响。无论我的报告多么遥远,我总是可以将事情扩展到瓶颈。 (拥有大量的线程和'IJob')这个库应该能够扩展到10个核心。 – Leo