我们有什么比BlockingCollection更好的异步执行方法?

我写了这样的例子来衡量BlockingCollection的异步执行速度

using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace TestBlockingCollection { class Program { static void Main(string[] args) { BlockingCollection blockingCollection = new BlockingCollection(); Stopwatch sw = Stopwatch.StartNew(); Task.Factory.StartNew(() => { int i = 0; while (true) { Console.WriteLine("Adding " + i); sw = Stopwatch.StartNew(); blockingCollection.Add(i++); Thread.Sleep(1000); } }); Task.Factory.StartNew(() => { while (true) { int i = blockingCollection.Take(); sw.Stop(); long microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)); Console.WriteLine("Received " + i + ". Spent " + microseconds + " microseconds."); } }); while(true) { Thread.Sleep(1000); } } } } 

结果令人失望:

 Adding 0 Received 0. Spent 19593 microseconds. Adding 1 Received 1. Spent 220 microseconds. Adding 2 Received 2. Spent 38 microseconds. Adding 3 Received 3. Spent 104 microseconds. Adding 4 Received 4. Spent 46 microseconds. Adding 5 Received 5. Spent 37 microseconds. Adding 6 Received 6. Spent 112 microseconds. Adding 7 Received 7. Spent 103 microseconds. Adding 8 Received 8. Spent 104 microseconds. Adding 9 Received 9. Spent 384 microseconds. Adding 10 Received 10. Spent 102 microseconds. Adding 11 Received 11. Spent 39 microseconds. Adding 12 Received 12. Spent 51 microseconds. Adding 13 Received 13. Spent 42 microseconds. Adding 14 Received 14. Spent 40 microseconds. Adding 15 Received 15. Spent 40 microseconds. Adding 16 Received 16. Spent 42 microseconds. Adding 17 Received 17. Spent 40 microseconds. Adding 18 Received 18. Spent 41 microseconds. Adding 19 Received 19. Spent 42 microseconds. Adding 20 Received 20. Spent 62 microseconds. Adding 21 Received 21. Spent 36 microseconds. Adding 22 Received 22. Spent 39 microseconds. Adding 23 Received 23. Spent 35 microseconds. Adding 24 Received 24. Spent 40 microseconds. Adding 25 Received 25. Spent 63 microseconds. Adding 26 Received 26. Spent 56 microseconds. Adding 27 Received 27. Spent 42 microseconds. Adding 28 Received 28. Spent 41 microseconds. Adding 29 Received 29. Spent 42 microseconds. Adding 30 Received 30. Spent 41 microseconds. Adding 31 Received 31. Spent 651 microseconds. Adding 32 Received 32. Spent 43 microseconds. Adding 33 Received 33. Spent 58 microseconds. Adding 34 Received 34. Spent 43 microseconds. Adding 35 Received 35. Spent 41 microseconds. Adding 36 Received 36. Spent 59 microseconds. Adding 37 Received 37. Spent 38 microseconds. Adding 38 Received 38. Spent 38 microseconds. Adding 39 Received 39. Spent 38 microseconds. Adding 40 Received 40. Spent 42 microseconds. Adding 41 Received 41. Spent 59 microseconds. Adding 42 Received 42. Spent 40 microseconds. Adding 43 Received 43. Spent 42 microseconds. Adding 44 Received 44. Spent 41 microseconds. Adding 45 Received 45. Spent 39 microseconds. Adding 46 Received 46. Spent 42 microseconds. Adding 47 Received 47. Spent 41 microseconds. Adding 48 Received 48. Spent 41 microseconds. Adding 49 Received 49. Spent 42 microseconds. Adding 50 Received 50. Spent 35 microseconds. Adding 51 Received 51. Spent 42 microseconds. Adding 52 Received 52. Spent 39 microseconds. Adding 53 Received 53. Spent 43 microseconds. Adding 54 Received 54. Spent 35 microseconds. Adding 55 Received 55. Spent 60 microseconds. Adding 56 Received 56. Spent 59 microseconds. Adding 57 Received 57. Spent 55 microseconds. Adding 58 Received 58. Spent 74 microseconds. Adding 59 Received 59. Spent 56 microseconds. Adding 60 Received 60. Spent 42 microseconds. 

平均而言,我花了大约50微秒,但有时我花了600微秒!

即使使用我的慢速奔腾U5400,我预计它应该是几个,不超过10个,不超过10微秒的常量。

.NET对async exec有什么更快的方法? 在异步执行exec后,我需要它尽快启动。 这是财务时间敏感的计算。

阻止收集保证订单和保证项目将逐个处理,所以这个问题实际上包含两个问题

  1. 如果我需要订购,我们是否有更快的东西?我需要按照它们出现的顺序处理物品? 即我需要FIFO查询。
  2. 如果我不关心订单,我们是否有更快的东西?我不关心物品是逐个处理还是平行处理?

我猜答案是:

  1. 不,我必须使用BlockingCollection,因为使用BlockingCollection 作为单生成器,单用户FIFO查询是否合适?

  2. 我可以试试代表吗? http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

经过几个小时的实验,我认为这是衡量阻碍的方法; 我改为运行10000,结果如下:

100000次迭代总计214.0,平均0.00214 ms

代码几乎和你的一样(以下是参考资料); 我做了一个发布版本

我尝试使用屏障,但速度较慢。 我也尝试使用锁只做但却无法正常工作。

  static void Main(string[] args) { var barrier = new Barrier(2); var collection = new List(); var num_iterations = 100000; var iterations = num_iterations; var total_time_ms = 0.0M; Stopwatch sw = new Stopwatch(); total_time_ms = 0.0M; iterations = num_iterations; var blockingCollection = new BlockingCollection(); Task.Factory.StartNew(() => { int i = 0; while (iterations-- > 0) { sw.Restart(); blockingCollection.Add(i++); } }); Task.Factory.StartNew(() => { var expected_value = 0; while (iterations > 0) // stop when performed certain number { int i = blockingCollection.Take(); sw.Stop(); long microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)); total_time_ms += microseconds; if (i != expected_value) Console.WriteLine(String.Format("** expected {0} got {1}", i, expected_value)); expected_value++; } }); while (iterations > 0) { Thread.Sleep(1000); } Console.WriteLine(String.Format("Total {0} for {1} iterations, average {2}", total_time_ms, num_iterations, total_time_ms / num_iterations)); 

我相信BlockingCollection是一个很好用的集合。 还有其他方法可以做到这一点,但这是一个复杂的领域,获得比这更快的东西的机会是不可能的。

首先,如果你真的关心微秒,也许你不应该使用.Net(因为它的垃圾收集器可以给你不可预测的延迟)或Windows(因为它不是实时操作系统)。

要真正回答你的问题:

  1. 我认为50微秒是一个非常短的时间,而且BlockingCollection是高度优化的,所以我认为你不能更快地做到这一点。 您可以使用自旋锁执行此操作,但代价是浪费CPU时间无所事事。

  2. 异步调用委托与使用ThreadPool.QueueUserWorkItem()几乎相同。 所以,是的,这可能接近你能得到的最好的。 虽然同步调用总是会更快。