.net c#等待异步事件完成的最佳方法,并且代码中仍然有"同步"流

Mic*_*ett 9 .net c# asynchronous

我的一般性问题是:如何编写仍然清晰易懂的异步代码,就像同步解决方案一样?

我的经验是,如果你需要使用像BackgroundWorker之类的东西来制作一些异步同步代码,你就不再需要一系列易于理解的程序语句来表达你的整体意图和活动顺序,你最终会得到一堆"完成"事件处理程序,每个事件处理程序启动下一个BackgroundWorker,生成非常难以遵循的代码.

我知道这不是很清楚; 更具体的东西:

假设我的WinForms应用程序中的一个函数需要启动一些amazon EC2实例,等待它们运行,然后等待它们全部接受SSH连接.伪代码中的同步解决方案可能如下所示:

instances StartNewInstances() {
    instances = StartInstances()
    WaitForInstancesToBecomeRunning(instances)
    WaitForInstancesToAcceptSSHConnection(instances).
    return (instances)
    }
Run Code Online (Sandbox Code Playgroud)

真好.发生的事情非常清楚,程序行动的顺序非常明确.没有白噪声会让您分心,无法理解代码和流程.我真的想最终得到类似的代码.

但实际上,我不能有一个同步解决方案..这些功能中的每一个都可以运行很长时间,每个功能都需要执行以下操作:更新ui,监视超时超时,并定期重试操作直到成功或超时.简而言之,这些中的每一个都需要在后台进行,因此前台UI线程可以继续.

但是,如果我使用像BackgroundWorker这样的解决方案,似乎我最终不会像上面那样容易理解程序逻辑.相反,我可能从我的UI线程启动后台工作程序来执行第一个函数,然后我的ui线程在工作线程运行时返回到UI.完成后,其"完成"事件处理程序可能会启动下一个后台工作程序.它完成后,其"完成"事件处理程序可能会启动最后一个BackgroundWorker,依此类推.这意味着您必须"完成事件处理程序的跟踪"才能理解整个程序流程.

必须有一种更好的方法:a)让我的UI线程能够响应,b)让我的异步操作能够更新ui,最重要的是c)能够将我的程序表达为一系列连续的步骤(就像我一样)如上所示),以便有人可以理解结果代码

任何和所有输入将不胜感激!迈克尔

Jon*_*eet 11

我的一般性问题是:如何编写仍然清晰易懂的异步代码,就像同步解决方案一样?

你等着C#5.现在不会很久.async/ await岩石.您已经在上面的句子中描述了该功能...请参阅Visual Studio异步主页以获取教程,语言规范,下载等.

目前,确实没有一种非常干净的方式 - 这就是为什么首先需要这个功能的原因.异步代码非常自然地变得一团糟,尤其是当您考虑错误处理等时.

您的代码将表示为:

async Task<List<Instance>> StartNewInstances() {
    List<Instance> instances = await StartInstancesAsync();
    await instances.ForEachAsync(x => await instance.WaitUntilRunningAsync());
    await instances.ForEachAsync(x => await instance.WaitToAcceptSSHConnectionAsync());
    return instances;
}
Run Code Online (Sandbox Code Playgroud)

这是假设一些额外的工作,例如IEnumerable<T>表单上的扩展方法

public static Task ForEachAsync<T>(this IEnumerable<T> source,
                                   Func<T, Task> taskStarter)
{
    // Stuff. It's not terribly tricky :(
}
Run Code Online (Sandbox Code Playgroud)