我想这是一个性能计算问题。我正在用C编写一个程序,它产生大量的输出,远远超过通常可以完整地存储在RAM中。我打算简单地将输出写入stdout
;所以它可能只是进入屏幕,或者可能被重定向到文件中。我的问题是如何为将存储在RAM中的数据选择最佳缓冲区大小?
输出数据本身并不是特别重要,所以我们只是说它产生了一个庞大的随机整数列表。
我打算有2个线程:一个产生数据并将其写入缓冲区,另一个将该缓冲区写入stdout
。这样,我可以开始生成下一个输出缓冲区,而前一个缓冲区仍然被写入stdout
。
要明确,我的问题不是关于如何使用malloc()
和pthread_create()
等函数。我的问题纯粹是关于如何选择多个字节(512,1024,1048576)对于最佳缓冲区大小,这将提供最佳性能?
理想情况下,我想找到一种可以动态选择最佳缓冲区大小的方法,这样我的程序就可以适应当时正在运行的硬件。我试过寻找这个问题的答案,虽然我发现了一些关于缓冲区大小的线程,但我找不到与此问题特别相关的任何内容。因此,我只是想把它作为一个问题发布,希望我能得到一些不同的观点,并提出比我自己更好的东西。
答案 0 :(得分:6)
混合设计和优化是一个很大的浪费时间。这被认为是top canonical mistakes.中的一个。它很可能会损坏您的设计而实际上并没有太多优化。
让您的程序正常运行,如果有性能问题的迹象,请对其进行分析,并考虑分析真正导致问题的部分。
我认为这尤其适用于复杂的架构优化,例如多线程应用程序。对单个图像进行多线程处理是您从未真正想要做的事情:它不可能进行测试,容易出现不可重现的错误,在不同的执行环境中会有不同的失败,还有其他问题。但是,对于某些程序,功能需要多线程并行执行,或者是获得必要性能的一种方法。它得到了广泛的支持,实际上它有时是一种必要的恶魔。
如果没有确凿的证据证明像你这样的程序需要它,那么在初始设计中你不需要它。
几乎任何其他并行方法(消息传递?)都将更容易实现和调试,无论如何,你在操作系统的I / O系统中获得了很多这样的方法。
答案 1 :(得分:1)
简短回答:衡量一下。
答案很长:根据我的经验,这在很大程度上取决于很难提前预测的因素。另一方面,您不必在开始之前提交自己。只需实现通用解决方案,完成后,进行一些性能测试并获得最佳结果的设置。分析器可以帮助您专注于程序中的性能关键部分。
从我所看到的,产生最快代码的那些代码,通常首先尝试最简单,直接的方法。比普通程序员做得更好的是他们在编写出色的性能测试方面有很好的技巧,这远远不是微不足道的。
没有经验,很容易陷入某些陷阱,例如,忽略缓存效果,或者(可能在您的应用程序中?!)低估了IO操作的成本。在最糟糕的情况下,你最终会挤压程序中对整体性能没有贡献的部分。
回到原来的问题:
在您描述的场景中(一个CPU绑定的生产者和一个IO绑定的消费者),很可能其中一个将成为瓶颈(除非生产者生成数据的速率变化很大)。根据哪一个更快,整个情况会发生根本变化:
让我们首先假设,IO绑定的使用者是你的瓶颈(无论是写入stdout还是写入文件都无关紧要)。可能的后果是什么?
优化算法以生成数据不会提高性能,而是必须最大化写入性能。但是,我认为写入性能不会非常依赖于缓冲区大小(除非缓冲区太小)。
在另一种情况下,如果生产者是限制因素,情况就会逆转。在这里,您必须分析生成代码并提高算法的速度,以及读者和编写器线程之间的数据通信。但是,缓冲区大小仍然无关紧要,因为缓冲区大部分时间都是空的。
当然,情况可能比我描述的更复杂。但除非你确定自己不是处于极端情况之一,否则我不会投入调整缓冲区大小。只是保持可配置,你应该没事。我不认为以后将其重新安装到其他硬件环境应该是一个问题。
答案 2 :(得分: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所花费的时间 - 是否会导致部分或全部差异?
答案 3 :(得分:0)
大多数现代操作系统都擅长将磁盘用作RAM的后备存储。我建议你把启发录留给操作系统,只需要你想要的内存,直到遇到性能瓶颈。
答案 4 :(得分:0)
无需使用缓冲,操作系统会在必要时自动将页面交换到磁盘,您无需编程。如果您不需要保存数据,那么简单就是让您留在RAM中,否则您最好在生成数据后保存它,因为它对磁盘i / o更好。