如何有效地执行50并行算法500次每秒? [英] how to execute 50 parallel methods 500 times per second effectively?

查看:146
本文介绍了如何有效地执行50并行算法500次每秒?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要执行 strategy.AllTablesUpdated(); 在2毫秒50策略(我需要重复的说〜500次每秒)。
使用下面的代码,我发现,刚 Monitor.TryEnter 通话用时最多的 1毫秒(!!!),我做50倍!

  //必须调用〜500每秒
公共无效FinishUpdatingTables倍()
{
的foreach(战略策略在策略)//约〜50,应以2毫秒
{
//这种缓慢和可并联
strategy.AllTablesUpdated()执行;
}
}



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

 公共覆盖布尔AllTablesUpdated(秒表SW)
{
本.sw = SW;
检查点(这+TryEnter尝试);
如果(Monitor.TryEnter(desiredOrdersBuy))
{
检查点(这+TryEnter成功);

{
OnAllTablesUpdated();
}最后
{
Monitor.Exit(desiredOrdersBuy);
}
返回真;
}否则
{
检查点(这+TryEnter失败);
}
返回FALSE;
}

公共无效的检查点(字符串消息)
{
如果(SW == NULL)
{
的回报;
}
长的时间= sw.ElapsedTicks /(Stopwatch.Frequency /(1000L * 1000L));
Log.Push(LogItemType.Debug,消息+时间);
}



从日志(以微秒),失败的尝试用时〜1ms的:





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





从日志(以微秒),成功的尝试用时〜0.01ms:





12:55:49:701调试:TryEnter尝试889
12时55分49秒: 701调试:TryEnter成功900





所以,现在我觉得显示器。 TryEnter 是太贵了,我一个50的策略执行的。所以,我想用并行这项工作工作这样的:

  / /必须调用每秒
公共无效FinishUpdatingTables〜500倍()
{
的foreach(战略策略在策略)//约〜50时,应在2毫秒
执行{
//这种缓慢和可并联
Task.Factory.StartNew(()=> {
strategy.AllTablesUpdated();
});
}
}



我也可能会替换 Monitor.TryEnter 只是锁定与这样的方法,一切都会是异步的。



我的问题:




  • 为什么 Monitor.TryEnter 是如此之慢? (如果1毫秒未获得锁)

  • 如何好是开始50 工作每2毫秒=每个任务的25 000第二? .NET可以有效管理呢?我还可以用生产者 - 消费者模式与 BlockingCollection 并启动50打工皇帝只有一次,然后提交的50项每2毫秒的新包,以BlockingCollection?那是不是更好?

  • 您会怎样执行50的方法可以并联各2毫秒(每秒500次),共每秒25万次?


解决方案

  1. Monitor.TryEnter(对象)只是Monitor.TryEnter(对象,0,裁判假)(0毫秒超时)。如果没有获得锁1毫秒只是试图获得锁的开销。

  2. 您可根据需要启动尽可能多的任务,他们都使用线程池,虽然这将是有限的线程的一个最大数目。最大取决于你的系统,核心数量,内存等上......这不会25,000线程,虽然是肯定的。但是,如果你开始与TPL调度meddeling你会惹上麻烦的。我只是用 Parallel.Foreach ,看看它能走多远我。

  3. Parallel.ForEach 。我还确保策略的类型为的IList ,以便尽可能多的项目都尽可能发射了无需等待上迭代器。



您还没有粘贴代码OnAllTablesUpdated(),您保留锁该程序的持续时间。这将是在所有liklihood瓶颈。



有些问题,你为什么要使用时,该表已准备好处理?

$ B锁
$ b

  1. 是代表不可能?

  2. 为什么当你正在运行的策略锁定?你修改每个策略里面的桌子吗?你不能把它的一个副本,如果是这样的话?


I need to execute strategy.AllTablesUpdated(); for 50 strategies in 2 ms (and I need to repeat that ~500 times per second). Using code below I discovered that just Monitor.TryEnter call spents up to 1 ms (!!!) and I do that 50 times!

    // 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);
    }

From logs (in µs), failed attempt spents ~ 1ms:

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

From logs (in µs), succeed attempt spents ~ 0.01ms:

12:55:49:701 Debug: TryEnter attempt 889 12:55:49:701 Debug: TryEnter success 900

So now I think that Monitor.TryEnter is too expensive for me to be executed one by one for 50 strategies. So I want to parallel this work using Task like that:

    // 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();
            });
        }
    }

I will also probably replace Monitor.TryEnter to just lock as with such approach everything will be asynchronous.

My questions:

  • Why Monitor.TryEnter is so slow ? (1 ms if lock is not obtained)
  • How good would be to start 50 Task each 2 ms = 25 000 of Tasks each second? Can .NET manage this effectively? I can also use producer-consumer pattern with BlockingCollection and start 50 "workers" only ONCE and then submit new pack of 50 items each 2 ms to BlockingCollection? Would that be better?
  • How would you execute 50 methods that can be paralleled each 2 ms (500 times per second), totally 25 000 times per second?

解决方案

  1. Monitor.TryEnter(object) is just Monitor.TryEnter(object, 0, ref false) (0 millisecond timeout). That 1 ms if the lock is not obtained is just overhead of trying to acquire a lock.
  2. You can start as many tasks as you like, they all use the ThreadPool though which will be limited to a maximum number of threads. The maximum is dependent on your system, number of cores, memory etc... It will not be 25,000 threads that's for sure though. However, if you start meddeling with the TPL scheduler you'll get into trouble. I'd just use Parallel.Foreach and see how far it gets me.
  3. Parallel.ForEach. I'd also ensure that strategies is of type IList so as many items are fired off as possible without waiting on an iterator.

You haven't pasted the code to OnAllTablesUpdated(), you keep the lock for the duration of that procedure. That's going to be your bottleneck in all liklihood.

Some questions, why are you using a lock for when the table is ready to be processed?

  1. Are delegates not possible?
  2. Why lock it when you're running the strategy? Are you modifying that table inside each strategy? Can you not take a copy of it if that is the case?

这篇关于如何有效地执行50并行算法500次每秒?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆