1

我有这样的代码:

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 秒。

但如果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 微秒)。所以转到另一个线程可能不是一个好主意,我认为一切都应该在同一个线程中完成。

4

1 回答 1

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 个硬线程,尽管如果它们已经存在,它可以使用它们),您可以消除大部分线程开销。如果不出意外,这是对当前选项和您创建的任何其他解决方案进行基准测试的一种选择。

于 2013-01-03T16:52:43.633 回答