Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the benefits of C# async/await in a serverless context?

For microservice functions that simply call an external service or write to a data store, is there any point to using async/await in C#?

We're writing a fair number of these in AWS Lambdas, and it's hard to determine what the actual gain of async/await is in this context or where exactly it would be useful. For more traditional IIS web services, the asynchrony frees up threads in the OS and allows the server to service more requests.

But for AWS Lambdas, the functions only handle a single request per execution (limited to 1000 simultaneous executions). So if we have a long-running external process or external dependency with significant latency, each function execution will be hung up until the external process completes (assuming the Lambda is invoked synchronously).

Here's a sample Lambda with three handlers, the third of which I put into a separate Lambda called "DavidSleep" which simply represents a long-running external dependency. When I invoke a different Lambda called "DavidTest" using either of the first two handlers, I see no functional or performance difference between the async/await version and the one lacking async/await. Both functions require multiple concurrent Lambda executions and take the same amount of time.

So the async version appears to have no difference to the async-less version, but is there any?

public class Test
{
    private IAmazonLambda lambda;

    public Test()
    {
        lambda = new AmazonLambdaClient();
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public async Task HandleAsync(Request request)
    {
        Console.WriteLine($"Executing for { request.Name }");
        await lambda.InvokeAsync(new InvokeRequest
        {
            FunctionName = "DavidSleep",
            InvocationType = InvocationType.RequestResponse,
            Payload = JsonConvert.SerializeObject(request)
        });
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public void Handle(Request request)
    {
        Console.WriteLine($"Executing for { request.Name }");
        lambda.InvokeAsync(new InvokeRequest
        {
            FunctionName = "DavidSleep",
            InvocationType = InvocationType.RequestResponse,
            Payload = JsonConvert.SerializeObject(request)
        }).Wait();
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public void Sleep(Request request)
    {
        Console.WriteLine($"{ request.Name }{ request.RequestId } begin");
        Thread.Sleep(request.WaitInSeconds * 1000);
        Console.WriteLine($"{ request.Name }{ request.RequestId } end");
    }
}
like image 793
David Avatar asked Sep 02 '25 14:09

David


2 Answers

Benefits of async/await in serverless context would still be that you are yielding control of the calling thread, freeing up another caller to use the thread. I don't know if AWS will remove an await call from the 1000 call limit, but they could potentially.

For these one liner style task calls with no other async calls in the method, you can simply return the Task. Marking the method async and calling await adds un-necessary overhead, regardless of the AWS Lambda 1000 call limit.

Example:

[LambdaSerializer(typeof(JsonSerializer))]
public Task HandleAsync(Request request)
{
    Console.WriteLine($"Executing for { request.Name }");
    return lambda.InvokeAsync(new InvokeRequest
    {
        FunctionName = "DavidSleep",
        InvocationType = InvocationType.RequestResponse,
        Payload = JsonConvert.SerializeObject(request)
    });
}
like image 75
jjxtra Avatar answered Sep 05 '25 02:09

jjxtra


There are 2 cases discussed here:

  • Async-await in C# code used in the Lambda function
  • Invoke a long-running lambda function asynchronously vs. synchronously

Async/Await pattern in C# code in a Lambda function
The Lambda execution framework does not care of how the code is being executed - it simply invokes the .Net framework to execute the code and waits for the execution to complete. And inside the function, it is the usual async/await pattern advantages.

The Async/await in C# code is useful if you are starting a long operation asynchronously and then using the main thread to do something different which is not dependent on the long operation's result. If there is a single long operation in the function, asynchronous and synchronous executions are similar. No advantage of using async over sync (in fact, as pointed out in the comments above, you may have a slight overhead of using the async mechanism).

Invoke a lambda function asynchronously vs. synchronously
The question describes an example of this difference - a long running lambda is called using an async method and a synchronous method. There is no change observed, for valid reasons.

Again an async call is beneficial only when the main thread can do something different not dependent on the async method's result. The example shows only a call to the lambda. So the main thread has to wait till its execution completes in both async and sync cases. It is not utilizing the wait time for other execution, hence there is no difference seen in the overall time taken for execution.

Scenario for Async
Let's say there are 2 lambda functions, DavidSleep and JohnSleep which need to be invoked in parallel, independent of each other. DavidSleep takes 1 sec to execute and JohnSleep takes 2 sec to execute.

If both these are called in the HandleAsync() above, the total execution time will be ~2 sec (plus a few ms for the async overhead)
If these are called in the Handle() above, the total execution time will be ~3 sec (plus a few ms)

like image 35
samiksc Avatar answered Sep 05 '25 02:09

samiksc