async Task() not returning straight away when not using await


async Task<T>() not returning straight away when not using await
If I have the following function
public async Task<bool> Foo()
{
// call many async functions
await Bar1().ConfigureAwait(false);
await Bar2().ConfigureAwait(false);
return await Bar3().ConfigureAwait(false);
}
If I call the function above
var t1 = Foo();
var t2 = Foo();
...
await Task.WhenAll(t1, t2).ConfigureAwait(false);
t2 will not execute until t1 completes, (so calling WaitAll
is a bit pointless).
WaitAll
But if I call
...
var t1 = Task.Run( async () => await Foo().ConfigureAwait(false));
var t2 = Task.Run( async () => await Foo().ConfigureAwait(false));
...
await Task.WhenAll(t1, t2).ConfigureAwait(false);
t1 and t2 return immediately...
And now if I run ...
...
var t1 = Task.Run( () => Foo());
var t2 = Task.Run( () => Foo());
...
await Task.WhenAll(t1, t2).ConfigureAwait(false);
t1 and t2 also return immediately...
Why does Foo() not return task immediately?
And, should I call Task.Run( () => Foo())
or Task.Run( async () => await Foo().ConfigureAwait(false))
Task.Run( () => Foo())
Task.Run( async () => await Foo().ConfigureAwait(false))
Yes, I print to console when
t1
start/complete, t2
start/completes and when WaitAll
starts/complete. Those are long running functions, so there is no way that t1
complete before t2
starts– Simon Goodman
9 mins ago
t1
t2
WaitAll
t1
t2
"t2 will not execute until t1 completes" -- t2 should execute as soon as t1 is first interrupted. If it is never interrupted, that suggests you don't actually have any async code in
Bar1
/Bar2
/Bar3
. Is that correct?– hvd
6 mins ago
Bar1
Bar2
Bar3
Hum, no, I have a few async code inside that function, (between 3 and 5). Those are database calls (Sqlite .NET).
– Simon Goodman
16 secs ago
1 Answer
1
Since ConfigureAwait(false)
"fixes" the problem, the issue is readily apparent. You're starting off in a single-threaded context (e.g. a UI thread). This means that all of the code that runs between your await
calls has to run on that one single thread. Which means that although you do start multiple tasks, they're unable to make progress in parallel.
ConfigureAwait(false)
await
Whether the code within Bar1
, Bar2
, etc is able to make progress in parallel across multiple calls is an implementation detail of those methods, so I cannot answer whether they're also bound to the same single thread.
Bar1
Bar2
Bear in mind, await
doesn't start anything. You hand it a Task
(or other awaitable) and it does, literally, just wait for it to finish (whilst not tying up whatever thread was running this method at the point we hit an await
). How that Task
will be completed, how it was started, etc, are all details irrelevant to await
.
await
Task
await
Task
await
The OP hasn't said
ConfigureAwait(false)
by itself fixes the problem, as far as I can tell. ConfigureAwait(false)
is only used combined with Task.Run
in the question. My guess was it was simply a long-running CPU-bound function, and it was Task.Run
that fixed it. (Edit: someone else edited the question to turn the erroneous ConfigureAwait()
into ConfigureAwait(false)
. If that is what the OP meant, then ConfigureAwait(false)
didn't "fix" anything.)– hvd
2 mins ago
ConfigureAwait(false)
ConfigureAwait(false)
Task.Run
Task.Run
ConfigureAwait()
ConfigureAwait(false)
ConfigureAwait(false)
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
how are you verifying those results? do you print to stdout or?
– smn.tino
12 mins ago