简体   繁体   English

等待异步动作

[英]Awaiting asynchronous actions

I've got a static generic method that is intended to perform an action on a collection in parallel (don't worry about throttling; I've got that covered; code here is the dumbed-down version): 我有一个静态通用方法,旨在并行地对一个集合执行操作(不用担心节流;我已经覆盖了;这里的代码是精简版):

public static IEnumerable<Task> RunAllAsync<T>(this IEnumerable<T> enumerable, Action<T> action)
{
    var tasks = new List<Task>();
    foreach (var t in enumerable)
    {
        tasks.Add(Task.Run(() => action(t)));
    }
    return tasks;
}

Here's an example of how the usage might be: 这是用法示例:

public async Task UsageSync()
{
    var numbers = Enumerable.Range(1, 5);
    var random = new Random();
    var tasks = numbers.RunAllAsync(i =>
                                    {
                                        Console.WriteLine($"A {i}");
                                        Thread.Sleep(random.Next(1000));
                                        Console.WriteLine($"B {i}");
                                    });
    Console.WriteLine("Awaiting end");
    await Task.WhenAll(tasks.ToArray());
    Console.WriteLine("awaited");
    Thread.Sleep(2000);
    Console.WriteLine("Finished");
}

Output: 输出:

Awaiting end
A 4
A 5
A 1
A 2
A 3
B 3
B 2
B 1
B 5
B 4
awaited
Finished

All as expected. 一切都如预期。 But now we make that action itself an async delegate: 但是现在我们使该动作本身成为异步委托:

public async Task UsageAsync()
{
    var numbers = Enumerable.Range(1, 5);
    var random = new Random();
    var tasks = numbers.RunAllAsync(async i =>
                                    {
                                        Console.WriteLine($"A {i}");
                                        await Task.Run(() =>
                                                       {
                                                           Console.WriteLine($"B {i}");
                                                           Thread.Sleep(random.Next(1000));
                                                           Console.WriteLine($"C {i}");
                                                       });
                                    });
    Console.WriteLine("Awaiting end");
    await Task.WhenAll(tasks.ToArray());
    Console.WriteLine("awaited");
    Thread.Sleep(2000);
    Console.WriteLine("Finished");
}

Output: 输出:

Awaiting end
A 4
B 4
A 1
A 5
A 3
A 2
B 2
awaited
B 5
B 1
B 3
C 3
C 2
C 1
C 5
C 4
Finished

See that? 看到了吗? The method reached "awaited" before the threads finished! 在线程完成之前,该方法已“等待”!

What should I be doing to ensure that the asynchronous action is awaited? 我应该怎么做才能确保等待异步操作?

Since you're dealing with an Action<T> , async i => { ... } gets translated into an async void method. 由于您正在处理Action<T> ,因此async i => { ... }被转换为async void方法。 async void by design makes it impossible to wait for it to finish. 设计上的async void使其无法等待完成。 Change your parameter to Func<T, Task> func and changing the call action(t) to await func(t) . 将您的参数更改为Func<T, Task> func并将调用action(t)更改为await func(t)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM