我有一段c# 5.0代码,它生成了大量的网络和磁盘I/O。我需要并行运行此代码的多个副本。以下哪一种技术可能会给我最好的性能:
-
异步方法
-
直接从TPL中使用Task
-
活性扩展
我不是很擅长这种并行的东西,但如果使用较低的杠杆,比如线程,可以给我更好的性能,我也会考虑。
这就像试图通过要求最快的方法解开安全带来优化跨大西洋航班的长度一样。
好吧,一些真正的建议,因为我有点混蛋
让我们给出一个有用的答案。把性能想象成活动的"类"——每一个都慢一个数量级(至少!):
- 只访问CPU,很少的内存使用(即渲染非常简单的图形到一个非常快的GPU,或计算π的数字)
- 只访问CPU和内存中的东西,不访问磁盘(即编写良好的游戏)
- 访问磁盘
- 接入网络
那么,我们可以从中得出什么?有两种方法可以使程序更快,要么从#3提高到#2(这通常是不可能的,取决于您正在做什么),要么通过减少I/O来。I/O和网络速度是大多数现代应用程序中的速率限制因素,而正是您应该尝试优化的。
面对"大量的网络和磁盘I/O",这些选项之间的任何性能差异都是无关紧要的。
一个更好的问题是"哪个选项最容易学习和发展?"或者"从现在开始的5年里,哪个选项对维护这个代码最好?"对于这一点,我建议首先是async
,或者数据流或Rx,如果你的逻辑更好地表示为流。
这是一个老问题,但是对于任何读到这篇文章的人…
视情况而定。如果您试图用50B的消息使1Gbps的链路饱和,那么即使通过原始套接字进行简单的非阻塞发送,也会受到CPU的限制。另一方面,如果您对1Mbps的吞吐量或大于10KB的消息感到满意,那么这些框架中的任何一个都可以完成这项工作。
对于低带宽情况,我建议按易用性排序,即async/await、Dataflow、Rx、TPL按此顺序排列。请注意,高带宽应用程序应该像低带宽应用程序一样进行原型设计,然后再进行优化。
对于真正的高带宽应用程序,我可以推荐Dataflow而不是Rx,因为Rx不是为高并发性设计的。原始TPL是底层,如果您可以处理复杂性,它可以保证最低的开销。如果您可以有效地使用专用线程,那么将会更快。在我看来,Async/await和Dataflow在性能上并没有什么区别。开销似乎可以比较,所以选择一个更合适的。