使用c#异步调用自定义消息

时间:2014-04-27 04:23:48

标签: c# asynchronous ui-thread async-await

我正在创建一个在单个线程上运行的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());
}

也许我走错了路。我很感激你的意见!

2 个答案:

答案 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,为您提供有关同步上下文如何工作的更多信息,以及关于从哪里开始编写自己的内容的一些想法。