首页 文章

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

提问于
浏览
2

我需要在2毫秒内执行 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调试:TryEnter尝试889 12:55:49:701调试:尝试输入成功900

所以现在我认为 Monitor.TryEnter 对我来说太昂贵了,不能一个接一个地执行50个策略 . 所以我希望使用_475020这样并行这项工作:

// 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 25秒= 25 000个任务有多好? .NET可以有效地管理这个吗?我也可以使用 BlockingCollection 的 生产环境 者 - 消费者模式,然后仅启动50 "workers" ONCE,然后每2毫秒向BlockingCollection提交50个项目的新包装?会更好吗?

  • 你如何执行50个方法,每2毫秒(每秒500次)可以并行,每秒总共25 000次?

1 回答

  • 4
    • Monitor.TryEnter(object)只是Monitor.TryEnter(object,0,ref false)(0毫秒超时) . 如果没有获得锁定,那1毫秒只是尝试获取锁定的开销 .

    • 您可以根据需要启动任意数量的任务,它们都使用ThreadPool,但这将限制为最大线程数 . 最大值取决于您的系统,内核数量,内存等...它不会是25,000个线程_475028会遇到麻烦 . 我只是使用 Parallel.Foreach ,看看它到底有多远 .

    • Parallel.ForEach . 我还要确保 strategies 的类型为 IList ,以便在不等待迭代器的情况下尽可能多地触发 .

    您尚未将代码粘贴到OnAllTablesUpdated(),您在该过程的持续时间内保持锁定 . 这将成为你所有可能性的瓶颈 .

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

    • 代表不可能吗?

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

相关问题