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);
继续,尽管 a
和 b
都没有完成(因为它们处于无限循环中)
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
。所以 a
和 b
不是 Task
,它们是 Task<Task>
。 Task.Factory.StartNew
此处仅启动一个任务,return 是您要等待的实际任务。
你可以在a
和b
上使用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);
}
}
await Task.WhenAll(a, b);
继续,尽管 a
和 b
都没有完成(因为它们处于无限循环中)
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
。所以 a
和 b
不是 Task
,它们是 Task<Task>
。 Task.Factory.StartNew
此处仅启动一个任务,return 是您要等待的实际任务。
你可以在a
和b
上使用Unwrap
来return一个代表整个操作的任务,意思是:
await Task.WhenAll(a.Unwrap(), b.Unwrap());
但是,Task.Run
更简单并且隐含地执行此操作。
await Task.WhenAll(a, b);
continues albeit neithera
norb
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);
}
}