我有这样的代码:
public void TablesUpdated(object sender, TablesUpdatedArgs args)
{
lock (quotesLock)
{
while (!args.quotesQueue.IsNullOrEmpty())
quotes.Enqueue(args.quotesQueue.Dequeue());
}
lock (securitiesLock)
{
while (!args.securitiesUpdates.IsNullOrEmpty())
securities.Enqueue(args.securitiesUpdates.Dequeue());
}
lock (orderUpdatesLock)
{
while (!args.orderUpdates.IsNullOrEmpty())
orderUpdates.Enqueue(args.orderUpdates.Dequeue());
}
}
此代码存在的问题是我正在等待lock
,而我可能会处理代码的其他部分。虽然我在等待代码的其他部分可能会被锁定!
假设quotesLock
在0到1秒之间忙,securitiesLock
在1到2秒之间忙,orderUpdatesLock
在2到3秒之间忙。由于订单,我的代码将被完全阻止3个seconods。
但如果qoutesLock
将是最后一个:
public void TablesUpdated(object sender, TablesUpdatedArgs args)
{
lock (securitiesLock)
{
while (!args.securitiesUpdates.IsNullOrEmpty())
securities.Enqueue(args.securitiesUpdates.Dequeue());
}
lock (orderUpdatesLock)
{
while (!args.orderUpdates.IsNullOrEmpty())
orderUpdates.Enqueue(args.orderUpdates.Dequeue());
}
lock (quotesLock)
{
while (!args.quotesQueue.IsNullOrEmpty())
quotes.Enqueue(args.quotesQueue.Dequeue());
}
}
代码将在1秒内执行。
问题是如何重写代码:
可能我应该用很多while
方法编写非常复杂的TryEnter
循环。或者更好的是什么?
upd 持续很短的时间(约5-15微秒)。所以去另一个线程可能不是一个好主意,我认为一切都应该在同一个线程中完成。
答案 0 :(得分:2)
由于这些任务完全不依赖于彼此,因此最好将它们平行化。
这是一种方法:
Parallel.Invoke(new ParallelOptions(), () =>
{
lock (securitiesLock)
{
while (!args.securitiesUpdates.IsNullOrEmpty())
securities.Enqueue(args.securitiesUpdates.Dequeue());
}
},
() =>
{
lock (orderUpdatesLock)
{
while (!args.orderUpdates.IsNullOrEmpty())
orderUpdates.Enqueue(args.orderUpdates.Dequeue());
}
},
() =>
{
lock (quotesLock)
{
while (!args.quotesQueue.IsNullOrEmpty())
quotes.Enqueue(args.quotesQueue.Dequeue());
}
});
由于你所说的锁被持有相当长的一段时间,这很可能是一场净胜利。因为它将依赖于线程池线程(因此很可能甚至不需要创建3个硬线程,尽管如果它们已经存在它们就可以使用它们),您可以消除大部分线程开销。如果不出意外,它可以选择针对当前选项和您创建的任何其他解决方案进行基准测试。