如何有效地每秒执行500次并行方法500次?

时间:2012-04-18 09:31:31

标签: c#

我需要在2 ms内执行strategy.AllTablesUpdated(); 50个策略(我需要重复每秒500次)。 使用下面的代码,我发现只有Monitor.TryEnter调用 1 ms (!!!)并且我这样做了50次!

    // must be called ~500 times per second
    public void FinishUpdatingTables()
    {
        foreach (Strategy strategy in strategies)   // about ~50, should be executed in 2 ms
        {
            // this slow and can be paralleled
            strategy.AllTablesUpdated();
        }
    }

...................

    public override bool AllTablesUpdated(Stopwatch sw)
    {
        this.sw = sw;
        Checkpoint(this + " TryEnter attempt ");
        if (Monitor.TryEnter(desiredOrdersBuy))
        {
            Checkpoint(this + " TryEnter success ");
            try
            {
                OnAllTablesUpdated();
            } finally
            {
                Monitor.Exit(desiredOrdersBuy);
            }
            return true;
        } else
        {
            Checkpoint(this + " TryEnter failed ");
        }
        return false;
    }

    public void Checkpoint(string message)
    {
        if (sw == null)
        {
            return;
        }
        long time = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
        Log.Push(LogItemType.Debug, message + time);
    }

从日志(以μs为单位),尝试失败〜1ms:

  
    

12:55:43:778调试:TryEnter尝试1264     12:55:43:779调试:TryEnter失败2123

  

从日志(以μs为单位),成功尝试花费~0.01ms:

  
    

12:55:49:701调试:尝试尝试889     12:55:49:701调试:尝试输入成功900

  

所以现在我觉得Monitor.TryEnter对我来说太昂贵了,不能一个接一个地执行50个策略。所以我希望使用Task来平行这项工作:

    // must be called ~500 times per second
    public void FinishUpdatingTables()
    {
        foreach (Strategy strategy in strategies)  // about ~50, should be executed in 2 ms
        {
            // this slow and can be paralleled
            Task.Factory.StartNew(() => {
                strategy.AllTablesUpdated();
            });
        }
    }

我也可能会将Monitor.TryEnter替换为lock,因为这种方法一切都是异步的。

我的问题:

  • 为什么Monitor.TryEnter这么慢? (如果未获得锁定,则为1 ms)
  • 每秒开始50 Task每2 ms = 25 000个任务有多好? .NET可以有效地管理这个吗?我也可以使用BlockingCollection的生产者 - 消费者模式,仅启动50个“工人”,然后每2毫秒向BlockingCollection提交50个项目的新包装?会更好吗?
  • 你如何执行50个方法,每2毫秒(每秒500次)可以并行,每秒总共25 000次?

1 个答案:

答案 0 :(得分:4)

  1. Monitor.TryEnter(object)只是Monitor.TryEnter(object,0,ref false)(0毫秒超时)。如果没有获得锁定,则为1 ms只是试图获取锁定的开销。
  2. 您可以根据需要启动任意数量的任务,但它们都使用ThreadPool,但这将限制为最大线程数。最大值取决于您的系统,内核数量,内存等......但这肯定不会是25,000个线程。但是,如果您开始使用TPL调度程序进行处理,则会遇到麻烦。我只是使用Parallel.Foreach,看看它到底有多远。
  3. Parallel.ForEach。我还要确保strategies的类型为IList,以便在不等待迭代器的情况下尽可能多地触发项目。
  4. 您尚未将代码粘贴到OnAllTablesUpdated(),您在该过程的持续时间内保持锁定。这将成为你所有可能性的瓶颈。

    有些问题,为什么在表准备好处理时使用锁?

    1. 代表不可能吗?
    2. 为什么在运行策略时将其锁定?您是否在每个策略中修改该表?如果是这样的话你能不复制一份吗?