Home > other >  Need help understanding background tasks in async/await calls in Azure Functions
Need help understanding background tasks in async/await calls in Azure Functions

Time:10-14

I've been creating a service using C# in Azure Functions. I've read guides on how the best usage of async/await but don't understand its value in the context of Azure functions.

In my Azure function, I have 3 calls being made to a external API. I tried to use async/await to kick off my API calls. The idea is that the the first two tasks return a list each, which will be concatenated, and then compared against the third list.

After this comparison is complete, all the items are then sent to a storage container queue, for processing by another function that uses a queue trigger.

My async implementation is below:

var firstListTask = GetResourceListAsync(1);
var secondListTask = GetResourceListAsync(2);
var thirdListTask = GetOtherResourceListAsync(1);

var completed = await Task.WhenAll(firstListTask, secondListTask);
var resultList = completed[0].Concat(completed[1]);

var compareList = await thirdListTask; 
// LINQ here to filter out resultList based on compareList

Running the above, I get an execution time of roughly 38 seconds. My understanding of the async implementation is that I kick off all 3 async calls to get my lists.

  • The first two tasks are awaited with 'await Task.WhenAll...' - at this point the thread exits the async method and 'does something else' until the API returns the payload
  • API payload is received, the method is then resumed and continues executing the next instruction (concatenating the two lists)
  • The third task is then awaited with 'await thirdListTask', which exits the async method and 'does something else' until the API returns the payload
  • API payload is received, the method is then resumed and continues executing the next instruction (filtering lists)

Now if I run the same code synchronously, I get an execution time of about 40 seconds:

var firstList = GetResourceList(1)
var secondList = GetResourceList(2);
var resultList = firstList.Concat(secondListTask)

var compaireList = GetOtherResourceList(1);
var finalList = // linq query to filter out resultList based on compareList

I can see that the async function runs 2 seconds faster than the sync function, I'm assuming this is because the thirdListTask is being kicked off at the same time as firstListTask and secondListTask?

My problem with the async implementation is that I don't understand what 'does something else' entails in the context of Azure Functions. From my understanding there is nothing else to do other than the operations on the next line, but it can't progress there until the payload has returned from the API.

Moreover, is the following code sample doing the same thing as my first async implementation? I'm extremely confused seeing examples of Azure Functions that use await for each async call, just to await another call in the next line.

var firstList = await GetResourceListAsync(1);
var secondList = await GetResourceListAsync(2);

var resultList = firstList.Concat(secondList);

var compareList= await GetOtherResourceListAsync(1);
// LINQ here to filter out resultList based on compareList

I've tried reading MS best practice for Azure Functions and similar questions around async/await on stackoverflow, but I can't seem to wrap my head around the above. Can anyone help simplify this?

CodePudding user response:

var firstListTask = GetResourceListAsync(1);
var secondListTask = GetResourceListAsync(2);
var thirdListTask = GetOtherResourceListAsync(1);

This starts all 3 tasks. All 3 API calls are now running.

var completed = await Task.WhenAll(firstListTask, secondListTask);

This async awaits until both tasks finish. It frees up the thread to go "do something else" What is this something else? Whatever the framework needs it to be. It's a resource being freed, so it could be used in running another async operation's continuation etc.

var compareList = await thirdListTask; 

At this point, your API call has most likely completed already, as it was started with the other 2. If it completed, the await will pull out the value or throw an exception if the task was faulted. If it is still ongoing, it will async wait for it to complete, freeing up the thread to "go do something else"

var firstList = await GetResourceListAsync(1);
var secondList = await GetResourceListAsync(2);

var resultList = firstList.Concat(secondList);

var compareList= await GetOtherResourceListAsync(1);

This is different from your first example. If e.g. all your API calls take 5 seconds to complete, the total running time will be 15 seconds, as you sequentially start and await for it to complete. In your first example, the total running time will roughly be 5 seconds, so 3 times quicker.

  • Related