我正在研究一种非常cpu密集的科学软件(它的proc界限),但它需要经常将数据写入磁盘(i / o绑定)。

我正在为此添加并行化(OpenMP),我想知道解决磁盘写入需求的最佳方法是什么。 仿真没有理由等待硬盘驱动器(这就是它现在正在做的事情)。

我正在为此寻找“最佳实践”,速度是我最关心的(这些可能是非常长的模拟)。

由于 〜亚历

初步想法:

有一个单独的进程执行实际写入磁盘,因此模拟有两个进程:一个是CPU绑定(模拟),一个是IO绑定(写入文件)。这听起来很复杂。

可能是管道/缓冲区?我对这些很新,所以也许这可能是一个可能的解决方案。

有帮助吗?

解决方案

如果您对程序实施OpenMP,那么最好使用并行部分中的 #pragma omp single #pragma omp master 来保存到文件。这些编译指示只允许一个线程执行某些操作。因此,您的代码可能如下所示:

#pragma omp parallel
{
    // Calculating the first part
    Calculate();

    // Using barrier to wait all threads
    #pragma omp barrier

    #pragma omp master
    SaveFirstPartOfResults();

    // Calculate the second part
    Calculate2();

    #pragma omp barrier

    #pragma omp master
    SaveSecondPart();

    Calculate3();

    // ... and so on
}

这里的线程团队将进行计算,但只有一个线程会将结果保存到磁盘。

它看起来像软件管道。我建议你考虑来自Intel Threading Building Blocks库的tbb :: pipeline模式。我可以参考软件管道教程 http://cache-www.intel.com/cd/00/00/30/11/301132_301132.pdf#page=25 。请阅读第4.2段。他们解决了这个问题:一个线程从驱动器读取,第二个线程处理读取字符串,第三个线程保存到驱动器。

其他提示

我想说最好的方法是生成一个不同的线程来保存数据,而不是一个全新的过程;使用新流程,您会遇到必须在整个流程边界上传输要保存的数据的麻烦,这会带来一系列新的困难。

首先想到的解决方案就是你所说的 - 在自己的进程中使用从SIM到写入器的单向管道进行磁盘写入。作者尽可能快地写入(从管道中提取新数据)。这样做的问题是,如果sim在编写器之前走得太远,那么无论如何sim都将在管道写入上被阻塞,并且它将在一次移除时被I / O绑定。

问题在于,实际上你的模拟周期没有完成,直到它吐出结果。

我发生的第二件事是使用非阻塞I / O.每当sim需要写入时,它应该通过非阻塞I / O来完成。在下一次需要写入时,它可以在启动新的I / O操作之前获取前一个I / O操作的结果(可能会产生一个小的等待)。这使得模拟尽可能与I / O并行运行,而不会让模拟在写入之前走得很远。

如果模拟处理周期变化(有时小于写入时间,有时更长),第一种解决方案会更好,因为平均来说,写入可能与sim卡保持同步。

如果处理周期总是(或几乎总是)短于写入时间  那么你也可以不用管道而只是使用非阻塞I / O,因为如果你使用管道,它最终会被填满,而且无论如何都会在I / O上挂起sim。

由于你是CPU和IO绑定的:我猜:还有足够的可用内存,对吧?

如果是这样,你应该将必须在内存中写入磁盘的数据缓冲到一定程度。编写大量数据通常比编写小块快得多。

写作本身:考虑使用内存映射IO。自从我进行基准测试以来已经有一段时间了,但是上次我这样做的速度要快得多。

此外,您可以随时交换CPU与IO。我认为您目前正在将数据写为某种原始的,未压缩的数据,对吧?如果使用简单的压缩方案来减少要写入的数据量,则可能会获得一些IO性能。 ZLIB库非常易于使用,并且在最低压缩级别上可以非常快速地压缩。这取决于数据的性质,但如果有很多冗余,即使是非常粗略的压缩算法也可能消除IO限制问题。

一个线程不断执行计算密集型过程的一个步骤,然后将部分结果添加到部分结果的队列中。另一个线程不断从队列中删除部分结果并将它们写入磁盘。确保同步对队列的访问。队列是类似于列表的数据结构,您可以在其中添加项目并从前面删除项目。

让您的应用程序有两个线程,一个用于CPU,一个用于硬盘。

让CPU线程将完成的数据推送到队列中,然后当数据进入时,硬盘线程将从中拉出。

这样CPU就可以摆脱数据并让其他人处理它,而硬盘驱动器只是耐心地等待队列中的任何数据。

实现方面,您可以将队列作为共享内存类型的对象,但我认为管道将是您正在寻找的。 CPU只需在需要时写入管道。在硬盘方面,您只需读取管道,无论何时获得有效数据,都可以从那里继续。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top