c# - 如何有效地每秒执行50个并行方法500次?

标签 c#

我需要执行strategy.AllTablesUpdated();在 2 毫秒内执行 50 个策略(我需要每秒重复大约 500 次)。 使用下面的代码我发现只是 Monitor.TryEnter通话时间长达 1 毫秒(!!!),我这样做了 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);
    }

从日志(以微秒为单位)来看,失败的尝试花费了约 1 毫秒:

12:55:43:778 Debug: TryEnter attempt 1264 12:55:43:779 Debug: TryEnter failed 2123

从日志(以微秒为单位)来看,成功尝试花费了约 0.01 毫秒:

12:55:49:701 Debug: TryEnter attempt 889 12:55:49:701 Debug: TryEnter success 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 毫秒)
  • 从 50 开始就好了 Task每 2 毫秒 = 每秒 25 000 个任务? .NET 可以有效地管理这个问题吗?我还可以使用 BlockingCollection 的生产者-消费者模式并仅启动 50 个“workers”一次,然后每 2 毫秒向 BlockingCollection 提交新的 50 个项目包?这样会更好吗?
  • 如何执行每 2 毫秒并行的 50 个方法(每秒 500 次),总共每秒 25,000 次?

最佳答案

  1. Monitor.TryEnter(object) 只是 Monitor.TryEnter(object, 0, ref false) (0 毫秒超时)。如果没有获得锁,那 1 毫秒只是尝试获取锁的开销。
  2. 您可以启动任意数量的任务,它们都使用线程池,但线程池的最大数量受到限制。最大值取决于您的系统、核心数量、内存等...但可以肯定的是,它不会是 25,000 个线程。然而,如果您开始干预 TPL 调度程序,您就会遇到麻烦。我只是使用 Parallel.Foreach 并看看它能让我走多远。
  3. Parallel.ForEach。我还要确保 strategies 的类型为 IList,以便在不等待迭代器的情况下触发尽可能多的项目。

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

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

  1. 委托(delegate)是不可能的吗?
  2. 为什么在运行策略时锁定它?您是否正在修改每个策略中的该表?如果是这样的话,你能不复印一下吗?

关于c# - 如何有效地每秒执行50个并行方法500次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10206624/

相关文章:

c# - 使用 C# LINQ 和 MongoDB 对嵌入/嵌套文档进行子查询或联接

c# - “HtmlAgilityPack.HtmlNode”不包含 'SelectNodes' 的定义

c# - WPF 组合框集合容器显示的文本

c# - 如何在不使用互操作的情况下通过 C# 取消隐藏 Excel 工作表

c# - 将参数化的 TestFixture 移动到基类后,NUnit 测试没有结果。为什么?

c# - 保护 .net 程序集

c# - 如何从 Caliburn.Micro ViewModel 制作文本框 ReadOnly?

c# - 如何在 .NET 中呈现与浏览器为文本提供 CSS 时相同的大小的文本

C# 运行批处理文件,无法识别命令

c# - 为 Release 编译的 UWP 中的 MissingTemplateException