Java 并行化任务,但在输出中保持输入顺序

Java 并行化任务,但在输出中保持输入顺序,java,parallel-processing,threadpool,Java,Parallel Processing,Threadpool,我有一个子系统,看起来像这样: [read] [decode] [deliver] Byte --> Undecoded --> Decoded --> Output queue stream message message 输入是套接字/字节流。第一步是阅读信息。下一步是解码消息(并将结果存储在消息对象中)。最后一步是传递信息 我想并行解码步骤,但我必须保持输

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

        [read]          [decode]       [deliver] 
Byte      -->  Undecoded  -->   Decoded   -->  Output queue
stream          message         message     
输入是套接字/字节流。第一步是阅读信息。下一步是解码消息(并将结果存储在消息对象中)。最后一步是传递信息

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

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

  • 运行单线程实现时为1100 K msg/s
  • 当运行一个简单的12线程实现时(具有大量 队列)
我的naive实现是在它有200多行代码的时候提供的,因此它可能只会让那些真正想知道如何使并行版本比串行版本慢10倍的人感兴趣(提示:开始查看ThreadPoolDecoder类)


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

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

单独的输出线程的预期记录编号从零开始。此线程监视队列,等待添加预期的记录号。添加预期记录后,线程将其从队列中移除,输出它,增加其预期记录编号,然后重试


这在我的应用程序中非常有效,有四个线程处理记录,一个线程处理输出。

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

单独的输出线程的预期记录编号从零开始。此线程监视队列,等待添加预期的记录号。添加预期记录后,线程将其从队列中移除,输出它,增加其预期记录编号,然后重试


这在我的应用程序中非常有效,有四个线程处理记录,一个线程处理输出。

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

1100 K msg/s的速度非常快(对于一条消息来说不到1微秒)。此时间与从队列中放入/获取消息的时间(0.1…1微秒)相当。因此,为了利用并行化,您必须将不间断处理的时间保持在1微秒(比如1毫秒)以上。如果将小消息组合成大消息,则可以完成此操作。在一个数据包中累积1000条消息,并将该数据包作为一个工作单元进行处理。并行处理单元。

我看到您手动创建线程。您是否考虑过使用ThreadPoolExecutor类?我看到您手动创建线程。您是否考虑过使用ThreadPoolExecutor类?