await Task.WhenAll(taskA, taskB) 继续,尽管 taskA 和 taskB 处于无限循环中(两者都在中间等待)

await Task.WhenAll(taskA, taskB) continues although taskA and taskB are in infinite loop (both with await in the middle)

await Task.WhenAll(a, b); 继续,尽管 ab 都没有完成(因为它们处于无限循环中)

public partial class App : Application, {
    protected override async void OnStartup(StartupEventArgs e) {
        var a = Task.Factory.StartNew(async () => {
            while (true) {
                Trace.WriteLine("A ->");
                await Task.Delay(TimeSpan.FromSeconds(0.1));
                Trace.WriteLine("-> A");
            }
        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
        var b = Task.Factory.StartNew(async () => {
            while (true) {
                Trace.WriteLine("B ->");
                await Task.Delay(TimeSpan.FromSeconds(0.09));
                Trace.WriteLine("-> B");
            }
        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    
        await Task.WhenAll(a, b);
        // I expected that the following line will never run, but it does:
        base.OnStartup(e);
    }
}

这是为什么?

编辑:

显然 editor/plugin/whatever 在这里误导了我:

不要使用 Task.Factory.StartNew。请改用 Task.Run

Task.Factory.StartNew 早于 async-await,因此它不期望异步委托(即 Func<Task>)。在那种情况下,它 return 是一个 Task<T>,其中 T 本身就是一个 Task。所以 ab 不是 Task,它们是 Task<Task>Task.Factory.StartNew 此处仅启动一个任务,return 是您要等待的实际任务。

你可以在ab上使用Unwrap来return一个代表整个操作的任务,意思是:

await Task.WhenAll(a.Unwrap(), b.Unwrap());

但是,Task.Run 更简单并且隐含地执行此操作。

await Task.WhenAll(a, b); continues albeit neither a nor b have completed

但是他们已经完成了。这正是 WhenAll 也完成的原因。您可以通过简单地及时检查任务的状态来自己看到这一点。

由于您将 async 方法传递给 StartNew,它将传递给 return 和 Task<Task>。一旦启动内部任务,外部任务就会完成。它不会等到内部任务完成后才完成。虽然您可以解包任务并将这些内部任务传递给WhenAll,但您也可以轻松地首先不包装任务 因为你这样做没有完成任何事情。

只需自己调用 async lambda 即可创建您想要的任务。

public partial class App : Application
{
    protected override async void OnStartup(StartupEventArgs e)
    {
        Func<Task> a = async () =>
        {
            while (true)
            {
                Trace.WriteLine("A ->");
                await Task.Delay(TimeSpan.FromSeconds(0.1));
                Trace.WriteLine("-> A");
            }
        };
        Func<Task> b = async () =>
        {
            while (true)
            {
                Trace.WriteLine("B ->");
                await Task.Delay(TimeSpan.FromSeconds(0.09));
                Trace.WriteLine("-> B");
            }
        };

        await Task.WhenAll(a(), b());
        base.OnStartup(e);
    }
}