gpt4 book ai didi

c# - 如何使使用队列线程的异步方法安全

转载 作者:太空狗 更新时间:2023-10-29 22:58:34 33 4
gpt4 key购买 nike

我有一项服务可以确保同时显示一个弹出窗口。 AddPopupAsync 可以并发调用,即打开一个弹出窗口,同时插入另外 10 个 AddPopupAsync 请求。代码:

public async Task<int> AddPopupAsync(Message message)
{
//[...]

while (popupQueue.Count != 0)
{
await popupQueue.Peek();
}

return await Popup(interaction);
}

但我可以发现由于缺乏线程安全而可能发生的两件不希望发生的事情:

  1. 如果队列为空,Peek 会抛出异常
  2. 如果线程 A 在 Popup 中的第一条语句之前被抢占,另一个线程 B 将不会等待挂起的弹出 A,因为队列仍然是空的。

Popup 方法与 TaskCompletionSource 一起使用,在调用其 SetResult 方法之前,调用 popupQueue.Dequeue()

我考虑使用 ConcurrentQueue 中的原子 TryPeek 来确保 #1 线程安全:

do
{
Task<int> result;

bool success = popupQueue.TryPeek(out result);

if (!success) break;
await result;
}
while (true);

然后我读到一个 AsyncProducerConsumerCollection但我不确定这是否是最简单的解决方案。

如何简单的保证线程安全?谢谢。

最佳答案

要简单地添加线程安全,您应该使用 ConcurrentQueue。它是队列的线程安全实现,您可以像使用队列一样使用它而无需担心并发性。

但是,如果您想要一个队列,您可以异步地await(这意味着您不会忙于等待或在等待时阻塞线程),您应该使用 TPL Dataflow 的 BufferBlock 这与 AsyncProducerConsumerCollection 非常相似,只是 MS 已经为您实现了:

var buffer = new BufferBlock<int>();
await buffer.SendAsync(3); // Instead of enqueue.
int item = await buffer.ReceiveAsync(); // instead of dequeue.

ConcurrentQueue 在线程安全方面很好,但在高级别争用中很浪费。 BufferBlock 不仅是线程安全的,它还为您提供异步协调(通常在消费者和生产者之间)。

关于c# - 如何使使用队列线程的异步方法安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27104992/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com