我在这里真的很奇怪,我缺少一些东西,但是现在已经为这个问题苦苦挣扎了几个小时,却无法解决。我有一种任务调度类,该类主要接收正常启动的同步操作,而不是通过Task.Run()异步启动。但是,当它获得传递的异步Action时,它将返回,而无需等待任务等待。我将其简化为以下示例:
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
Logger("Click event received");
await OperationProcessor(async () =>
{
Logger(">>> Starting ACTION, waiting 5 seconds");
await Task.Delay(5000);
Logger(">>> ACTION finished");
});
Logger("Click event finished");
}
private static async Task OperationProcessor(Action operation)
{
Logger("Processing started, waiting a second");
await Task.Delay(1000);
Logger("Launching action");
await Task.Run(operation);
Logger("Returned from action, waiting another second");
await Task.Delay(1000);
Logger("Processing finished");
}
private static void Logger(string message)
{
Console.WriteLine($"{DateTime.Now:dd.MM.yy HH:mm:ss} [{Thread.CurrentThread.ManagedThreadId}] {message}");
}
这将产生以下输出:
1: 16.07.19 10:58:06 [1] Click event received
2: 16.07.19 10:58:06 [1] Processing started, waiting a second
3: 16.07.19 10:58:07 [1] Launching action
4: 16.07.19 10:58:07 [7] >>> Starting ACTION, waiting 5 seconds
5: 16.07.19 10:58:07 [1] Returned from action, waiting another second
6: 16.07.19 10:58:08 [1] Processing finished
7: 16.07.19 10:58:08 [1] Click event finished
8: 16.07.19 10:58:12 [7] >>> ACTION finished
如何使5等待开始于4的动作?
答案 0 :(得分:1)
当您传递异步调用时,您不需要将其重新包装在线程中
您需要做的就是
private static async Task OperationProcessor(Action operation)
{
Logger("Processing started, waiting a second");
await Task.Delay(1000);
Logger("Launching action");
operation();
Logger("Returned from action, waiting another second");
await Task.Delay(1000);
Logger("Processing finished");
}
尽管您发现异步操作的签名正在返回一个任务,所以对异步调用的操作将相同
private static async Task OperationProcessor(Func<Task> operation)
{
Logger("Processing started, waiting a second");
await Task.Delay(1000);
Logger("Launching action");
await operation();
Logger("Returned from action, waiting another second");
await Task.Delay(1000);
Logger("Processing finished");
}
答案 1 :(得分:1)
为什么不等待传递给Task.Run()的异步动作?
因为不可能await
和void
。
谈论“等待方法”或“等待委托”是很常见的做法,但这可能会引起误解。实际发生的情况是该方法先被调用,然后等待 returns 。并且不可能等待Action
的结果,因为该委托返回了void
。
这是avoid async void
很好的主要原因。在这种情况下,async void
有点偷偷摸摸,因为它是lambda表达式。
与void Method()
异步等效的是async Task MethodAsync()
,因此asynchronous delegate equivalent of Action
is Func<Task>
。这就是为什么添加Func<Task>
重载起作用的原因。您可以同时保留Action
和Func<Task>
重载,并且编译器会明智地选择Func<Task>
lambda作为async
重载。
我有一种任务调度类
如果您的Func<Task>
解决方案足够好,请保持现状。但是,如果您想更深入一点,可以检测(并等待)async void
方法。 async void
个方法interact with the current SynchronizationContext
。由于您拥有自己的“计划课程”,因此您可能要考虑为该课程计划的代码提供SynchronizationContext
。如果您有兴趣,请随时向我的AsyncContext
class借用,它实际上只是带有SynchronizationContext
的单线程工作队列。
答案 2 :(得分:0)
知道了...更改方法签名可以完成以下任务:
private static async Task OperationProcessor(Func<Task> operation) {
// Body unchanged
}