I'm trying to understand some more about async/await
and particularly how the compiler knows to "pause" at an async
method and await
without spawning additional threads.
As an example, let's say I have an async
method like
DoSomeStuff();
await sqlConnection.OpenAsync();
DoSomeOtherStuff();
I know that await sqlConnection.OpenAsync();
is where my method gets "suspended" and the thread that invoked it returns to the thread pool and once the Task
that is tracking the connection opening completes then an available thread is found to run DoSomeOtherStuff()
.
| DoSomeStuff() | "start" opening connection | ------------------------------------ |
| ---------------------------------------------------------- | DoSomeOtherStuff() - |
Here's where I get confused. I look at the source code of OpenAsync
(https://referencesource.microsoft.com/#System.Data/System/Data/Common/DBConnection.cs,e9166ee1c5d11996,references) and it's
public Task OpenAsync() {
return OpenAsync(CancellationToken.None);
}
public virtual Task OpenAsync(CancellationToken cancellationToken) {
TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
if (cancellationToken.IsCancellationRequested) {
taskCompletionSource.SetCanceled();
}
else {
try {
Open();
taskCompletionSource.SetResult(null);
}
catch (Exception e) {
taskCompletionSource.SetException(e);
}
}
return taskCompletionSource.Task;
}
I imagine to see some place where the compiler would know to "cut off" the thread because the task has begun communicating with an external resource, but I don't really see that, and in fact, the Open();
seems to imply that it is synchronously waiting. Can someone explain how this becomes threadless "true async" code?