3

我想这是一个性能计算问题。我正在用 C 编写一个程序,它产生大量的输出,远远超过通常可以完全存储在 RAM 中的输出。我打算简单地将输出写入stdout;所以它可能只是进入屏幕,或者可能被重定向到文件中。我的问题是如何为将存储在 RAM 中的数据选择最佳缓冲区大小?

输出数据本身并不是特别重要,所以我们可以说它正在生成大量随机整数列表。

我打算有 2 个线程:一个产生数据并将其写入缓冲区,另一个将该缓冲区写入stdout. 这样,我可以在前一个缓冲区仍在写入时开始生成下一个输出缓冲区stdout

需要明确的是,我的问题不是关于如何使用等函数malloc()pthread_create()我的问题纯粹是关于如何为最佳缓冲区大小选择多个字节(512、1024、1048576),这将提供最佳性能?

理想情况下,我想找到一种可以动态选择最佳缓冲区大小的方法,以便我的程序可以适应当时正在运行的任何硬件。我试图寻找这个问题的答案,虽然我发现了一些关于缓冲区大小的线程,但我找不到任何与这个问题特别相关的东西。因此,我只是想把它作为一个问题发布,希望我能得到一些不同的观点,并提出比我自己更好的东西。

4

5 回答 5

6

混合设计和优化是浪费时间。这被认为是最典型的错误之一。它可能会损坏您的设计,并且实际上不会进行太多优化。

让您的程序正常工作,如果有迹象表明存在性能问题,则对其进行分析并考虑分析真正导致问题的部分。

我认为这尤其适用于复杂的架构优化,例如多线程应用程序。对单个图像进行多线程处理是您从未真正想做的事情:无法测试,容易出现无法重现的错误,在不同的执行环境中失败的方式不同,还有其他问题。但是,对于某些程序,多线程并行执行是功能所必需的,或者是获得必要性能的一种方式。它得到了广泛的支持,本质上它有时是一种必要的邪恶。

如果没有确凿的证据表明像您这样的程序需要它,这不是您在初始设计中想要的东西。

几乎任何其他的并行方法(消息传递?)都将更容易实现和调试,而且无论如何你都会在你的操作系统的 I/O 系统中得到很多。

于 2013-01-18T19:04:06.370 回答
1

简短的回答:测量它。

长答案:根据我的经验,这太依赖于难以提前预测的因素。另一方面,您不必在开始之前就做出承诺。只需实施一个通用解决方案,完成后,进行一些性能测试并获得最佳结果的设置。分析器可以帮助您专注于程序中的性能关键部分。

据我所见,那些产生最快代码的人通常首先尝试最简单、直接的方法。比普通程序员做得更好的是,他们拥有编写良好性能测试的非常好的技术,这远远不是微不足道的。

如果没有经验,很容易陷入某些陷阱,例如,忽略缓存效果,或者(可能在您的应用程序中?!)低估 IO 操作的成本。在最坏的情况下,您最终会挤压程序中对整体性能毫无贡献的部分。

回到你原来的问题:

在您描述的场景中(一个 CPU 密集型生产者和一个 IO 密集型消费者),其中一个很可能会成为瓶颈(除非生产者生成数据的速率变化很大)。取决于哪个更快,整个情况会发生根本性的变化:

让我们首先假设,IO 绑定消费者是您的瓶颈(无论它是写入标准输出还是写入文件)。可能的后果是什么?

优化生成数据的算法不会提高性能,相反,您必须最大限度地提高写入性能。但是,我假设写入性能不会在很大程度上取决于缓冲区大小(除非缓冲区太小)。

在另一种情况下,如果生产者是限制因素,则情况相反。在这里,您必须分析生成代码并提高算法的速度,并可能提高读取器和写入器线程之间的数据通信。但是,缓冲区大小仍然无关紧要,因为无论如何缓冲区大部分时间都是空的。

当然,情况可能比我描述的要复杂。但是,除非您确实确定自己不是处于极端情况之一,否则我不会投资调整缓冲区大小。只要保持可配置,你应该没问题。我认为以后将其改装到其他硬件环境应该不是问题。

于 2013-01-18T19:05:03.993 回答
1

我个人认为你是在浪费时间。

第一次运行time ./myprog > /dev/null

现在,使用 time dd if=/dev/zero of=myfile.data bs=1k count=12M.

dd是一个尽可能简单的程序,它会很快地写入文件。但是写入几千兆字节仍然需要一点时间。(我的机器上 12G 大约需要 4 分钟 - 这可能不是世界上最快的磁盘 - 与 /dev/null 相同大小的文件大约需要 5 秒)。

您可以在组合产生的位置尝试一些不同的数字,bs=x count=y与测试运行的程序输出大小相同。但我只发现如果你制作非常大的块,它实际上需要更长的时间(每次写入 1MB - 可能是因为操作系统需要先复制 1MB 才能写入数据,然后将其写出然后复制下一个 1MB,其中较小的块(我测试了 1k 和 4k),复制数据所需的时间要少得多,实际上“磁盘旋转在我们写入之前没有做任何事情”的情况更少)。

将这两个时间与您的程序运行时间进行比较。写入文件所需的时间是否dd比程序写入文件的时间短得多?

如果没有太大差异,请查看使用您的程序写入 /dev/null 所需的时间 - 这是部分或全部差异的原因吗?

于 2013-01-18T21:45:44.593 回答
0

大多数现代操作系统都擅长将磁盘用作 RAM 的后备存储。我建议您将启发式方法留给操作系统,并要求尽可能多的内存,直到遇到性能瓶颈。

于 2013-01-18T19:06:52.833 回答
0

无需使用缓冲,操作系统会在必要时自动将页面交换到磁盘,您无需对其进行编程。如果您不需要保存数据,最简单的方法是让您留在 RAM 中,否则您可能最好在生成数据后保存它,因为它对磁盘 i/o 更好。

于 2013-01-18T19:37:18.107 回答