问题
I think I missunderstanding the behaviour of async
await
in c#.
I have two methods that return a Task
defined like
public async Task Name()
{
await AsyncOperation()
}
Imagine AsyncOperation()
like an PostAsync
of HttpClient
.
Now I call them inside some other methods
public asyn Task Method()
{
await Name1(() => { "bla bla"});
await Name2();
Console.WriteLine("Continue");
}
This works as expected to me. Waits until Name1()
and Name2()
finish and then continues.
Now I need to nest Name1()
and Name2()
. In fact Name1()
is a Please Wait Window that recieve as lambda parameters a slow operation, while Name2()
is a slow download of a file. I want the Plese Wait window appears while the file is downloaded.
So I try something like this:
public asyn Task Method()
{
await Name1( async ()=>
{
await Name2();
}
Console.WriteLine("Continue");
}
In this case the execution doesnt wait untile Name2()
finished. Why this happen and await
doesnt wait?
Update
This is the logic behind the method of please wait. It shows a Please Wait message using Mahapps Dialogs, executes the code that recieves by the lambda, and then close the please wait message.
public static async Task Name1(Action longOperation)
{
_progressController = await _metroWindow.ShowProgressAsync("Please wait...");
await Task.Run(() => longOperation());
await _progressController.CloseAsync();
}
回答1:
The Name1
method takes a delegate and returns a Task<T>
where T
is the type returned by the delegate. In your case, the delegate returns Task
, so we get Task<Task>
as the result. Using await
waits only for the completion of the outer task (which immediately returns the inner task) and the inner task is then ignored.
You can fix this by dropping the async and await in the lambda function.
Also, take a look at Asynchronous Gotchas in C#.
回答2:
Name1 is expecting an argument of action, but what you really want is a func. In other words, Name1 should look something like this:
public static double Name1(Func<Task> longOperation)
{
longOperation().Wait();
}
Alternatively, wrap your action in a func and await it.
public static double Name1(Action longOperation)
{
Func<Task> f = async () => { longOperation(); };
f.Wait();
}
If you await an async sub, then the sub runs in the background but does not block the continuing execution of the calling method.
If you want to execute a sub and wait for it to complete before continuing with downstream logic, then convert your async subs to async functions (with a result type of threading.tasks.task when there is no actual return value).
This site has some great examples of common mistakes people make with async await: https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/
来源:https://stackoverflow.com/questions/24718724/nested-async-await-does-not-wait