如何有效地执行50并行算法500次每秒? [英] how to execute 50 parallel methods 500 times per second effectively?
问题描述
我需要执行 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万次?
解决方案
- Monitor.TryEnter(对象)只是Monitor.TryEnter(对象,0,裁判假)(0毫秒超时)。如果没有获得锁1毫秒只是试图获得锁的开销。
- 您可根据需要启动尽可能多的任务,他们都使用线程池,虽然这将是有限的线程的一个最大数目。最大取决于你的系统,核心数量,内存等上......这不会25,000线程,虽然是肯定的。但是,如果你开始与TPL调度meddeling你会惹上麻烦的。我只是用
Parallel.Foreach
,看看它能走多远我。
Parallel.ForEach
。我还确保策略
的类型为的IList
,以便尽可能多的项目都尽可能发射了无需等待上迭代器。
您还没有粘贴代码OnAllTablesUpdated(),您保留锁该程序的持续时间。这将是在所有liklihood瓶颈。
有些问题,你为什么要使用时,该表已准备好处理?
$ B锁
$ b
- 是代表不可能?
- 为什么当你正在运行的策略锁定?你修改每个策略里面的桌子吗?你不能把它的一个副本,如果是这样的话?
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 justMonitor.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 usingTask
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 justlock
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 withBlockingCollection
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?
解决方案
- 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.
- 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.Parallel.ForEach
. I'd also ensure thatstrategies
is of typeIList
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?
- Are delegates not possible?
- 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屋!