我正在创建一个在单个线程上运行的UI处理逻辑。基本上,我正在做的是
void HandlerMain()
{
while (true)
{
Task[] events = PumpEvents();
Task.WaitAll(events);
}
}
PumpEvents()
返回的一个示例任务是
async Task ButtonClick()
{
var httpClient = new HttpClient();
string s = await httpClient.GetStringAsync("http://microsoft.com");
Console.WriteLine(s);
}
我的代码问题是,如果其中一个events
需要很长时间,那么它会停留在Task.WaitAll()
,因此它无法提取新事件响应。除了WaitAll()
之外还有其他方法吗
Task[] remainingEvents = PumpEvents();
while (true)
{
remainingEvents = WaitUntilEveryTasksAwait(remainingEvents);
remainingEvents.Append(PumpEvents());
}
也许我走错了路。我很感激你的意见!
答案 0 :(得分:1)
如果我理解,你实际上不需要等到那些任务完成才能继续。只需删除对Task.WaitAll
的通话即可。
对于记录,Task.WaitAll
是同步的 - 它会阻止。最好使用Task.WhenAll
,它返回一个任务,该任务在所有提供的任务完成时完成。这让你等待它就像你等待任何单个任务一样。这样做可以解决问题,并保持用户界面的响应。
E.g:
async Task HandlerMain()
{
while (true)
{
Task[] events = PumpEvents();
await Task.WhenAll(events);
}
}
当然,在这种情况下,根据调用HandlerMain
的内容,您仍然遇到PumpEvents
挂起等待长时间运行任务的问题。
这开始引导问题的路径,例如,“当WPF和WinForms已经解决了问题时,为什么要编写自己的自定义UI消息泵?”
答案 1 :(得分:1)
@ScottChamberlain否。内置的UI处理器,比如WPF,正确处理异步事件,因此每当异步事件“等待”时,它都会跳过当前上下文并处理下一个事件。我想复制这种行为
根据您对我的评论,我现在明白您的问题是什么。您需要比简单while(true)
循环更多的逻辑才能处理await
消息。整个系统是在类SynchronizationContext
上构建的,你需要做的是从SynchronizationContext
派生你自己的类,并覆盖它的方法来排队你的工作在你的while循环中完成。 / p>
请参阅Stephen Cleary的this article,为您提供有关同步上下文如何工作的更多信息,以及关于从哪里开始编写自己的内容的一些想法。