How to use Async/Await Asp . Net Core correctly

Asked

Viewed 38 times

1

I am using asynchronous requests in various parts of the project, but a doubt has arisen because I know that for a method to be asynchronous it is necessary the same being async and have a await.

But we have some methods in Service that is async and has several await calls to Repository, staying as in the example below:

public async Task DoSomethingAsync()
        var url1 = await GetUrlFromBaseAsync(1);
        var url2 = await GetUrlFromBaseAsync(2);
        var url3 = await GetUrlFromBaseAsync(3);
        var file1 = await GetFileBlobStorageAsync(url1);
        var file2 = await GetFileBlobStorageAsync(url2);
        var file3 = await GetFileBlobStorageAsync(url3);

        //outras chamadas...
        Send(file1,file2,file3);
    }

When debugging it seems that each of these calls await are called only when another ends and not synchronously.

I know you have resources that really should be expected to continue, but I was hoping that the Urls would be searched at the same time or at least the search for the files in the blobStorage.

Someone could indicate if using async in this way is not being well utilized?

  • The operation is correct, when we use async/awat the compiler generates a background waiting state. That is, this is done asynchronously, your program is waiting for the task to finish. This makes the program flow is not blocked.

  • But is there any way to synchronize it?

1 answer

1

An important detail to note is that an asynchronous operation is different from a parallel operation. Using async/await this way allows asynchronous execution, which allows you to start an execution and have a callback (the C#Task) to act on the return, when it is ready.

In your case, by placing the await on each call, you are explicitly saying that you want to wait for the result of the operation before continuing the execution of your method. This is a valid form of async/await use, but it is not the one you are wanting by your question.

An example of implementing your methods just to illustrate what happens:

        private async Task<string> GetUrlFromBaseAsync(int i)
        {
            Debug.WriteLine($"{DateTime.Now:HH:mm:ss}: Iniciando GetUrlFromBaseAsync - {i}");

            await Task.Delay(TimeSpan.FromSeconds(2));

            Debug.WriteLine($"{DateTime.Now:HH:mm:ss}: Finalizando GetUrlFromBaseAsync - {i}");

            return $"https://www.site{i}.com.br";
        }

        private async Task<string> GetFileBlobStorageAsync(string url)
        {
            Debug.WriteLine($"{DateTime.Now:HH:mm:ss}: Iniciando GetFileBlobStorageAsync - {url}");

            await Task.Delay(TimeSpan.FromSeconds(5));

            Debug.WriteLine($"{DateTime.Now:HH:mm:ss}: Finalizando GetFileBlobStorageAsync - {url}");

            return string.Empty;
        }

So if you run as you put it in the question, it should show in the output a sequential execution, in which each waited for its end to start executing the next:

21:20:47: Iniciando GetUrlFromBaseAsync - 1
21:20:49: Finalizando GetUrlFromBaseAsync - 1
21:20:49: Iniciando GetUrlFromBaseAsync - 2
21:20:51: Finalizando GetUrlFromBaseAsync - 2
21:20:51: Iniciando GetUrlFromBaseAsync - 3
21:20:53: Finalizando GetUrlFromBaseAsync - 3
21:20:53: Iniciando GetFileBlobStorageAsync - https://www.site1.com.br
21:20:58: Finalizando GetFileBlobStorageAsync - https://www.site1.com.br
21:20:58: Iniciando GetFileBlobStorageAsync - https://www.site2.com.br
21:21:03: Finalizando GetFileBlobStorageAsync - https://www.site2.com.br
21:21:03: Iniciando GetFileBlobStorageAsync - https://www.site3.com.br
21:21:08: Finalizando GetFileBlobStorageAsync - https://www.site3.com.br

I’ll give you some examples of simple ways to execute these methods without waiting, but I won’t include loops and the like to facilitate the example, I’ll keep the calls similar to what you put.

One way is this:

            var taskUrl1 = GetUrlFromBaseAsync(1);
            var taskUrl2 = GetUrlFromBaseAsync(2);
            var taskUrl3 = GetUrlFromBaseAsync(3);

            await Task.WhenAll(taskUrl1, taskUrl2, taskUrl3);

            var taskFile1 = GetFileBlobStorageAsync(taskUrl1.Result);
            var taskFile2 = GetFileBlobStorageAsync(taskUrl2.Result);
            var taskFile3 = GetFileBlobStorageAsync(taskUrl3.Result);

            await Task.WhenAll(taskFile1, taskFile2, taskFile3);

            //outras chamadas...
            Send(taskFile1.Result, taskFile2.Result, taskFile3.Result);

With the Task.Whenall(), you specify that you want to wait for the execution of several Tasks before continuing to the next step. Output looks like this:

21:27:27: Iniciando GetUrlFromBaseAsync - 1
21:27:27: Iniciando GetUrlFromBaseAsync - 2
21:27:27: Iniciando GetUrlFromBaseAsync - 3
21:27:29: Finalizando GetUrlFromBaseAsync - 1
21:27:29: Finalizando GetUrlFromBaseAsync - 3
21:27:29: Finalizando GetUrlFromBaseAsync - 2
21:27:29: Iniciando GetFileBlobStorageAsync - https://www.site1.com.br
21:27:29: Iniciando GetFileBlobStorageAsync - https://www.site2.com.br
21:27:29: Iniciando GetFileBlobStorageAsync - https://www.site3.com.br
21:27:34: Finalizando GetFileBlobStorageAsync - https://www.site1.com.br
21:27:34: Finalizando GetFileBlobStorageAsync - https://www.site2.com.br
21:27:34: Finalizando GetFileBlobStorageAsync - https://www.site3.com.br

Another possibility, since you have in your example a method using the return of the other, is to execute the two methods of the same index in the same Task:

            var task1 = Task<string>.Run(async () => 
            {
                var url = await GetUrlFromBaseAsync(1);
                return await GetFileBlobStorageAsync(url);
            });

            var task2 = Task<string>.Run(async () =>
            {
                var url = await GetUrlFromBaseAsync(2);
                return await GetFileBlobStorageAsync(url);
            });

            var task3 = Task<string>.Run(async () =>
            {
                var url = await GetUrlFromBaseAsync(3);
                return await GetFileBlobStorageAsync(url);
            });

            await Task.WhenAll(task1, task2, task3);

            Send(task1.Result, task2.Result, task3.Result);

The output was very similar:

21:35:34: Iniciando GetUrlFromBaseAsync - 1
21:35:34: Iniciando GetUrlFromBaseAsync - 2
21:35:34: Iniciando GetUrlFromBaseAsync - 3
21:35:36: Finalizando GetUrlFromBaseAsync - 2
21:35:36: Finalizando GetUrlFromBaseAsync - 1
21:35:36: Finalizando GetUrlFromBaseAsync - 3
21:35:36: Iniciando GetFileBlobStorageAsync - https://www.site1.com.br
21:35:36: Iniciando GetFileBlobStorageAsync - https://www.site3.com.br
21:35:36: Iniciando GetFileBlobStorageAsync - https://www.site2.com.br
21:35:41: Finalizando GetFileBlobStorageAsync - https://www.site2.com.br
21:35:41: Finalizando GetFileBlobStorageAsync - https://www.site3.com.br
21:35:41: Finalizando GetFileBlobStorageAsync - https://www.site1.com.br

Browser other questions tagged

You are not signed in. Login or sign up in order to post.