I/O性能 - 异步 vs TPL vs Dataflow vs RX

22

我有一段生成大量网络和磁盘I/O的C# 5.0代码,需要并行运行多个副本。以下哪种技术可能会给我最好的性能:

  • 使用await的async方法

  • 直接使用TPL中的Task

  • TPL Dataflow nuget

  • 响应式扩展

我对这个并行化的东西不是很擅长,但如果使用像Thread这样的低级技术可以给我更好的性能,我也会考虑。


我没有理解nuget的上下文,为什么它只与TPL-Dataflow一起使用?你是在使用.NET 4.0的Async CTP还是.NET 4.5? - Gennady Vanin Геннадий Ванин
3个回答

66

这就像试图通过询问最快的方法来解除安全带来优化你的跨大西洋航班的长度。

好吧,因为我有点儿粗鲁,下面是真正的建议:

把性能看作“活动”的类别-每个活动都比上一个慢一个数量级(至少是这样!):

  1. 仅访问CPU,很少使用内存(即向非常快的GPU渲染非常简单的图形或计算Pi的位数)
  2. 仅访问CPU和内存中的东西,没有磁盘上的数据(即编写良好的游戏)
  3. 访问磁盘
  4. 访问网络

如果您执行了#3活动之一,那么进行典型于#1和#2活动的优化(如优化线程库)将毫无意义,因为它们完全被磁盘操作所掩盖。如果您不断产生L2 / L3高速缓存未命中,则手写汇编代码省略了一些CPU周期没有价值(这就是为什么如展开循环这样的东西现在通常是个坏主意)。

那么,我们能从中得出什么呢?要使程序更快,有两种方法,要么从#3升级到#2(这通常取决于您在做什么),要么减少I/O操作。在大多数现代应用程序中,I/O和网络速度是限制速率的因素,因此您应该尝试进行优化。


8
让程序变快的另一种方法是以更聪明的方式执行IO操作。例如,在使用传统硬盘驱动器时,通常不并行执行IO操作会更快,因为这会导致更多的寻道(这很慢)。 - svick
4
这也是个好主意。通过测量顺序读取速度和读取磁盘上随机扇区的速度,然后比较差异,就可以相对容易地检测出固态硬盘(SSD)。如果它们相似,那么你就有一个SSD。 - Ana Betts
3
@svick 我认为这是错误的,因为并行IO更快,由于使用SCAN和电梯算法,实际上能够更好地安排读取。 - yoel halb
我认为你是错误的,因为对于不同位置的两个显式顺序读取集合,总是比同时访问这两个位置具有更少的寻道次数,即使你正在重新排列I/O。 - Ana Betts
1
精彩的文章。我还可以补充一点,硬件对于第三点有很大的影响。一个标准的旋转硬盘可能只能做到100个IOPS(每秒输入/输出操作数),中档的固态硬盘可能做到6,000个IOPS,而高端的PCI Express固态硬盘可能在100,000个IOPS和10,000,000个IOPS之间。而未来20年的读者将会嘲笑这些数字。 - Contango

25
任何这些选项之间的性能差异都不足为奇,因为面对“大量的网络和磁盘I/O”,而更好的问题是:“哪个选项最容易学习和开发?”或者“哪个选项在未来五年内维护代码最好?”对于这一点,我建议首先选择async,如果您的逻辑更适合表示为流,则选择Dataflow或Rx。

16

这是一个老问题,但对于任何看到这个的人...

这取决于情况。如果您尝试使用50B消息饱和1Gbps链路,则即使使用简单的非阻塞原始套接字发送,您也会被CPU限制。另一方面,如果您满意1Mbps吞吐量或您的消息大于10KB,则任何这些框架都可以胜任。

对于低带宽情况,我建议按易用性进行优先排序,即按顺序为async/await、Dataflow、Rx、TPL。请注意,高带宽应用程序应首先以低带宽的方式进行原型开发,然后进行优化。

对于真正的高带宽应用程序,我推荐Dataflow而不是Rx,因为Rx不适用于高并发。原始TPL是底层,如果您能处理复杂性,则保证具有最低的开销。如果您可以有效地利用专用线程,则速度将更快。在Async/await与Dataflow之间,我认为没有性能差异。开销似乎相当,所以选择更适合自己的那个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接