I have an async
method like this:
public async Task SpecifyAsync()
{
CancellationTokenSource source = new();
Task<long> checkTask = BeginCheckingAsync(source.Token);
SendMessage();
await сheckTask;
}
Async method is called at its second line. As far as I understand, this shouldn't block main execution thread. However, third line is unreachable until checkTask
is finished. Can you, please, describe me, what am I doing wrong?
UPD. BeginCheckingAsync
code is something like this:
private async Task<long> BeginCheckingAsync(CancellationToken cancellationToken)
{
while (true)
{
var messages = _apiClient.GetNewMessages();
foreach (var message in messages)
if (ValidateMessage(message))
return await Task.FromResult(Parse(message));
cancellationToken.ThrowIfCancellationRequested();
}
}
There are two issues with your method:
await Task.FromResult
) is not an asynchronous operation, so it will not result in control passed to the caller.await
in the BeginCheckingBalanceAsync
will be executed synchronously, i.e. if _apiClient.GetNewMessages
is a long-running operation or ValidateMessage
will return false
for some iterations, everything before awaiting first "truly async" call would be executed synchronouslyDepending on actual implementations you can use Task.Run
in appropriate parts of the method. For example:
private async Task<long> BeginCheckingBalanceAsync(CancellationToken cancellationToken)
{
while (true)
{
var messages = await Task.Run(() => _apiClient.GetNewMessages());
foreach (var message in messages)
if (ValidateMessage(message))
return await Task.FromResult(Parse(message));
cancellationToken.ThrowIfCancellationRequested();
}
}
But according to the answer for Should I expose asynchronous wrappers for synchronous methods?:
My short answer to such a question is “no.”
Just use Task.Run
on the caller side, do not make BeginCheckingAsync
async itself.
Some potentially useful links: