使用c#异步调用的自定义消息泵送
本文关键字:自定义消息 调用 异步 使用 | 更新日期: 2023-09-27 18:00:25
我正在创建自己的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()
上,所以它不能引发新的事件,从而使UI没有响应。除了WaitAll()
,还有其他类似的方法吗
Task[] remainingEvents = PumpEvents();
while (true)
{
remainingEvents = WaitUntilEveryTasksAwait(remainingEvents);
remainingEvents.Append(PumpEvents());
}
也许我走错了路。我很感激你的建议!
@ScottChamberlain否。内置的UI处理器,比如WPF,可以正确地处理异步事件,所以每当异步事件"等待"时,它就会跳过当前上下文,处理下一个事件。我想复制这种行为
根据你对我的评论,我现在明白了你的问题是什么。你需要比简单的while(true)
循环更多的逻辑才能处理await
消息。整个系统是建立在类SynchronizationContext
上的,您需要做的是从SynchronizationContext
派生您自己的类,并覆盖它的方法,以便在while循环中排队完成您的工作。
请参阅Stephen Cleary的这篇文章,为您提供更多关于同步上下文如何工作的信息,并可能提供一些关于从哪里开始编写自己的想法。
如果我理解的话,您实际上不需要等到这些任务完成后才能继续。只需删除对Task.WaitAll
的调用。
对于记录,Task.WaitAll
是同步的——它会阻塞。您最好使用Task.WhenAll
,它返回一个在所有提供的任务完成时完成的任务。这让你可以像等待任何一项单独的任务一样等待它。这样做可以解决问题并保持UI的响应性。
例如:
async Task HandlerMain()
{
while (true)
{
Task[] events = PumpEvents();
await Task.WhenAll(events);
}
}
当然,在这种情况下,根据调用HandlerMain
的内容,您仍然会遇到PumpEvents
挂断等待长时间运行的任务的问题。
这开始引出一些问题,比如"当WPF和WinForms已经解决了这个问题时,为什么要编写自己的自定义UI消息泵?"