gpt4 book ai didi

c# - 对队列任务使用锁是一种好习惯吗?

转载 作者:太空宇宙 更新时间:2023-11-03 20:51:13 24 4
gpt4 key购买 nike

我需要将一些可以随时到达的请求放入队列中,这样每个任务仅在前一个任务结束时才开始。问题是,为此目的使用锁定是个好主意吗?它是否有任何不良影响,是否会导致我预期的排队行为?

更具体地说,考虑代码:

private int MyTask() {
...
}

private object someLock = new object();

public Task<int> DoMyTask() {
return Task.Run(() =>
{
lock (someLock)
{
return MyTask();
}
});
}

public void CallMyTask() {
var result = await DoMyTask();
}

请注意,CallMyTask() 将随时调用,可能同时调用。

最佳答案

is it a good idea to use locking for this purpose? Does it have any bad effects, and do the queuing behavior that I expect result from this?

锁定在这里不是一个好的解决方案。不良影响是它会阻塞一个线程池线程从工作在队列中直到工作完成。因此,如果您的代码排队 1000 个请求,它将调用 Task.Run 1000 次,并可能用完该数量的线程池线程,每个线程都在等待锁。

此外,锁并不是严格意义上的 FIFO。他们只是大多数-sorta-FIFO。这是因为严格 FIFO 锁会导致其他问题,例如锁车队; the links in this issue have some great discussion about lock "fairness" (i.e., FIFO behavior) .

所以,我推荐一个实际的队列。您可以使用 ActionBlock<T>来自 TPL Dataflow充当真正的队列。由于您的请求有结果,您可以使用TaskCompletionSource<T>使排队代码能够获得结果。 TaskCompletionSource<T>是一个“异步信号”——在本例中,我们使用它来通知调用代码他们的特定请求已通过队列并已执行。

private ActionBlock<TaskCompletionSource<int>> queue =
new ActionBlock<TaskCompletionSource<int>>(tcs =>
{
try { tcs.TrySetResult(MyTask()); }
catch (Exception ex) { tcs.TrySetException(ex); }
});

每次我们发送一个TaskCompletionSource<T>对此 queue ,它将运行 MyTask()并捕获结果(无论是成功还是异常),并将这些结果传递给 TaskCompletionSource<T> .

然后我们可以像这样使用它:

public Task<int> DoMyTask() {
var tcs = new TaskCompletionSource<int>();
queue.Post(tcs);
return tcs.Task;
}

public void CallMyTask() {
var result = await DoMyTask();
}

关于c# - 对队列任务使用锁是一种好习惯吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55086603/

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