gpt4 book ai didi

c# - 以非阻塞方式调用 TaskCompletionSource.SetResult

转载 作者:IT王子 更新时间:2023-10-29 04:21:50 27 4
gpt4 key购买 nike

我发现 TaskCompletionSource.SetResult(); 在返回之前调用等待任务的代码。就我而言,这会导致死锁。

这是在普通Thread中启动的简化版本

void ReceiverRun()
while (true)
{
var msg = ReadNextMessage();
TaskCompletionSource<Response> task = requests[msg.RequestID];

if(msg.Error == null)
task.SetResult(msg);
else
task.SetException(new Exception(msg.Error));
}
}

代码的“异步”部分看起来像这样。

await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();

Wait 实际上嵌套在非异步调用中。

SendAwaitResponse(简化)

public static Task<Response> SendAwaitResponse(string msg)
{
var t = new TaskCompletionSource<Response>();
requests.Add(GetID(msg), t);
stream.Write(msg);
return t.Task;
}

我的假设是第二个 SendAwaitResponse 将在 ThreadPool 线程中执行,但它会在为 ReceiverRun 创建的线程中继续执行。

有没有办法在不继续等待代码的情况下设置任务的结果?

该应用程序是一个控制台应用程序

最佳答案

I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.

是的,我有一个 blog post记录这个(AFAIK它没有记录在MSDN上)。死锁的发生有两个原因:

  1. 混合了 async 和阻塞代码(即 async 方法正在调用 Wait)。
  2. 使用 TaskContinuationOptions.ExecuteSynchronously 安排任务延续。

我建议从最简单的解决方案开始:删除第一件事 (1)。即,不要混合使用 asyncWait 调用:

await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();

相反,始终使用 await:

await SendAwaitResponse("first message");
await SendAwaitResponse("second message");

如果需要,您可以在调用堆栈更上层的替代点等待(async 方法中)。

这是我最推荐的解决方案。但是,如果您想尝试删除第二件事 (2),您可以使用一些技巧:将 SetResult 包装在 Task.Run 中以强制执行一个单独的线程(我的 AsyncEx library 具有执行此操作的 *WithBackgroundContinuations 扩展方法),或者为您的线程提供实际上下文(例如我的 AsyncContext type )并指定 ConfigureAwait(false) ,这将 cause the continuation to ignore the ExecuteSynchronously flag .

但这些解决方案比仅仅分离 async 和阻塞代码要复杂得多。

作为旁注,请查看 TPL Dataflow ;听起来您可能会发现它很有用。

关于c# - 以非阻塞方式调用 TaskCompletionSource.SetResult,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19481964/

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