2012-06-19 99 views
2

我有一个二进制文件,其中包含信息块(我将其称为数据包)。每个数据包由一个固定长度的头部和一个可变长度的主体组成。我必须从包头本身确定身体的长度。我的任务是从文件中读取这些数据包并对它们执行一些操作。目前我正在执行此任务,如下所示:Java - 并行读取二进制文件

  • 将文件作为随机访问文件打开并转到特定的起始位置(用户指定的起始位置)。从这个位置读取第一个数据包。在一个循环
    • 读取下一个数据包
    • 执行我的操作 执行具体操作
    • 那么这个推移,直到我打文件标志的结束。

正如您可以猜到,当文件大小是巨大的,连续读取每个数据包并处理它是一个耗时的事情。我想以某种方式将这个操作(即数据包生成操作)并行化并将其放入某个阻塞队列中,然后从队列中并行检索每个数据包并执行我的操作。

有人可以建议我怎么可以并行生成这些数据包?

+0

每个数据包头文件中的位置(第一个之后)是否取决于前面的数据包的大小? –

+0

@Ted:不是。我根据读取字节的特定签名来检测下一个数据包头的开始。它会在前一个数据包结束后的某处出现,但不会出现在任何特定位置。 – Sujay

回答

5

您应该只有一个线程在文件中按顺序读,因为我假设该文件位于一个驱动器。读取文件受限于您的IO速度,因此在CPU中并行化没有意义。事实上,由于常规硬盘驱动器专为顺序IO而设计,因此非顺序读取实际上会显着降低性能。对于读入的每个数据包,应该将该对象放入线程安全队列中。

现在您可以开始并行处理数据包。创建多个线程并让它们分别从队列中读取数据包。每个线程都应该进行处理并将其放入一些“完成”队列中。

IO线程读完文件后,应设置一个标志,以便在队列为空时工作线程停止。

+0

+1,尽管现代SSD可能会使连续文件的并行读取仍然比顺序读取更快。 – sarnold

+0

@sarnold:这可能是对的。虽然我没有足够的经验对w/SSD架构做出任何说明,但P – tskuzzy

+0

+1用于阻止多线程读取,这对性能非常重要。 –

0

我猜已知的快速方法是使用java.nio.MappedByteBuffer

+0

这听起来像是一个简单的内存映射。如何使用它来发现存储在非标准化字节边界上的数据包? – sarnold

+0

如果头部有长度,至少可以跳过数据包 - 如果不是,则执行并行扫描并调整!这绝对是一种将块预加载到内存并扫描它们比使用文件指针更快的方法,并且提前 –

3

如果您在使用盘片(即不是SSD)时使用磁盘,那么没有任何一个线程读取该文件是没有意义的,因为您所要做的只是将磁盘抖动,导致磁盘臂引入毫秒延迟。如果你有一个固态硬盘它是一个不同的故事,你可以平行阅读。

相反,你应该有一个线程从文件中读取数据,并创建数据包,然后执行以下操作:

  • 等待对已初始化为某编号的共享信号“A”(将是你“最大缓冲的分组”计数)
  • 锁定的共享对象
  • 分组附加到一个链表
  • 信号的另一个共享信号“B”(这一个跟踪分组在缓冲器中的计数)

然后,可以有许多其他的线程执行以下操作:在“B”旗语

  • 等待(以确保有将要处理的数据包)
  • 锁定共享对象
  • 做在链表getFirst()和该分组存储在本地变量
  • 信号旗语“A”,以允许另一分组到缓冲的包列表

这将确保您通过以连续的顺序对数据包进行条带化(尽快从磁盘中读取数据包),并确保您一次处理多个数据包而无需轮询。

+0

谢谢@AnthonyM您的建议!我猜你们和上一个答案都指向同一方向,即并行处理数据包,而不是并行访问文件。 – Sujay