并行化任务但保留输出中的输入顺序

时间:2012-04-16 14:40:25

标签: java parallel-processing threadpool

我有一个看起来像这样的子系统:

        [read]          [decode]       [deliver] 
Byte      -->  Undecoded  -->   Decoded   -->  Output queue
stream          message         message     

输入是套接字/字节流。第一步是阅读消息。下一步是解码消息(并将结果存储在消息对象中)。最后一步是传递信息。

我想并行化解码步骤,但我必须保持输出顺序与输入顺序相同。因此,如果收到消息A和B并且消息B的解码速度更快,我必须等到A完成传送它。

我在Java中做了一个天真的初始实现,但是我的分析表明我在切换步骤中丢失了太多(从“流读取器”到“解码器”以及从“解码器”到输出)。在24核计算机上运行测试程序(包括超线程)时,我得到:

    运行单线程实现时,
  • 1100 K msg / s。
  • 运行一个简单的12线程实现时,
  • 110 K msg / s(有很多 队列)。

我的天真实现可以在http://pastebin.com/be1JqZy3获得它超过200行代码,所以它可能只会让那些真正想知道如何使并行版本比串行速度慢10倍的人感兴趣(提示:开始看一下ThreadPoolDecoder类。

在执行此类问题时是否有任何人使用模式/框架,其中工作是继续的(基于流)可以并行化但必须在输出时进行排序?

2 个答案:

答案 0 :(得分:2)

我在我编写的程序(在C#中)处理这个问题的方法是在输出上有一个优先级队列。每条记录都有一个相关的记录号,在读取时分配。这些数字从0开始增加。线程完成处理记录后,会将记录添加到优先级队列中。

单独的输出线程具有从零开始的预期记录编号。该线程监视队列,等待添加的预期记录号。添加预期记录后,线程将其从队列中删除,输出,增加其预期记录编号,然后再次尝试。

这在我的应用程序中运行良好,有四个线程处理记录和一个处理输出。

答案 1 :(得分:2)

1100 K msg / s非常快(消息不到1微秒)。此时间与从队列中放入/获取消息的时间(0.1 ... 1微秒)相当。因此,为了利用并行化,您必须将不间断处理的时间显着更多地保持在1微秒(例如,1毫秒)。如果您将小消息组合成较大的消息,则可以执行此操作。在数据包中累积1000条消息,并将数据包作为一个工作单元处理。并行处理单元。