作为快速响应,如果您正在处理单个文件并写入另一个文件,则使用 openMP 可以轻松地将程序的顺序版本转换为多线程版本,而无需过多关注 IO 部分,前提是计算算法本身可以并行化。
这是真的,因为通常主线程负责 IO。如果由于数据块太大而无法一次读取,并且计算算法无法处理较小的块而无法做到这一点,则可以使用 openMP API 来同步每个线程中的 IO。这并不意味着整个应用程序将停止或等待其他线程完成计算才能读取或写入新数据,这意味着只需要原子地完成读取和写入部分。
例如,如果您的顺序应用程序的流程如下:
1) Read
2) compute
3) Write
鉴于它确实可以并行化,并且需要从每个线程中读取每个数据块,因此每个线程可以遵循下一个设计:
1) Synchronized read of chunk from input (only one thread at the time could execute this section)
2) Compute chunk of data (done in parallel)
3) Synchronized write of computed chunk to output (only one thread at the time could execute this section)
如果您需要以与读取它们相同的顺序写入块,则需要先缓冲,或者采用不同的策略,例如 fseek 到正确的位置,但这实际上取决于输出文件大小是否从一开始就已知,. ..
请特别注意 openMP 调度策略,因为默认值可能不是最适合您的计算算法的。如果您需要在线程之间共享结果,例如您已读取的输入文件的偏移量,您可以使用 openMP API 提供的归约操作,这比让代码的单个部分在所有线程之间原子运行要高效得多,只是为了更新一个全局变量,openMP 知道何时可以安全写入。
编辑:
关于“读、处理、写”操作,只要你在每个工人之间保持每次读写原子性,我想你不会有任何麻烦。即使读取的数据存储在内部缓冲区中,让每个工作人员以原子方式访问它,数据也会以完全相同的顺序获取。您只需要在将该块保存到输出文件时特别注意,因为您不知道每个工作人员将完成处理其属性块的顺序,因此,您可以准备好保存一个块,该块在其他块之后读取仍在处理中。您只需要每个工作人员跟踪每个块的位置,并且您可以保留指向需要保存的块的指针列表,直到您拥有自最后一个保存到输出文件以来的一系列完成的块。
如果您担心内部缓冲区本身(并且请记住,我不知道您正在谈论的库,所以我可能是错的)如果您向某些数据块发出请求,则应该只修改该内部缓冲区在您请求该数据之后和数据返回给您之前;并且当您以原子方式发出该请求时(意味着每个其他工作人员都需要排队等候),当下一个工作人员请求他的数据时,该内部缓冲区应该处于与最后一个工作人员收到其数据时相同的状态块。即使在库特别说明它返回一个指向内部缓冲区位置的指针而不是块本身的副本的情况下,您也可以在释放整个原子读取操作的锁之前复制到工作人员的内存。
如果正确遵循我建议的模式,我真的认为您不会发现在同一顺序版本的算法中找不到的任何问题。