13

In an async method where the code is not awaiting anything, is there a reason why someone would mark it async, await the task, and then return?

Besides the potential un-necessity of it, what are the negative ramifications of doing so?

For this example, please assume that QueryAsync<int> returns Task<int>.

private static async Task<int> InsertRecord_AsyncKeyword(SqlConnection openConnection)
{
    int autoIncrementedReferralId =
        await openConnection.QueryAsync<int>(@"
            INSERT INTO...
            SELECT CAST(SCOPE_IDENTITY() AS int)"
    );

    return autoIncrementedReferralId;
}

private static Task<int> InsertRecord_NoAsyncKeyword(SqlConnection openConnection)
{
    Task<int> task =
        openConnection.QueryAsync<int>(@"
            INSERT INTO...
            SELECT CAST(SCOPE_IDENTITY() AS int)"
    );

    return task;
}

// Top level method
using (SqlConnection connection = await DbConnectionFactory.GetOpenConsumerAppSqlConnectionAsync())
{
    int result1 = await InsertRecord_NoAsyncKeyword(connection);
    int result2 = await InsertRecord_AsyncKeyword(connection);
}
contactmatt
  • 18,116
  • 40
  • 128
  • 186
  • Hope that you might wanted to [safely call an async method in without await](http://stackoverflow.com/questions/15522900/how-to-safely-call-an-async-method-in-c-sharp-without-await) – Mohit S Jan 13 '17 at 01:51
  • Method that use `async` and not both are the same from the perspective of caller. Both are method that return `Task`. `async` keyword just enable you to use `await` inside the method, not the caller. – Niyoko Jan 13 '17 at 01:54
  • @NiyokoYuliawan I'm curious if awaiting earlier than expected would have any performance implications. – contactmatt Jan 13 '17 at 01:55
  • That said - assuming you trust users of your code to use the method correctly - no, there's no benefit that I can see. – Rob Jan 13 '17 at 02:01
  • Possible duplicate of [At the end of an async method, should I return or await?](http://stackoverflow.com/questions/17886992/at-the-end-of-an-async-method-should-i-return-or-await) – chwarr Jan 13 '17 at 02:09
  • @Rob I don't see how extra `await` will provide any ordering guarantees - `QueryAsync` will be *started* whether you `await` it or not and will not finish earlier than it can whether you `await` it directly or twice with nested `await`... Maybe you should post it as answer with sample. – Alexei Levenkov Jan 13 '17 at 02:11
  • 1
    @Rob it will run in parallel in both versions (assuming QueryAsync is really asynchronous). `await` has no impact on starting Task (as synchronous portion of the code runs the same in both cases). – Alexei Levenkov Jan 13 '17 at 02:18
  • @AlexeiLevenkov Sorry - you're absolutely correct, I've gone and confused myself with it. I'll delete the incorrect comments I've made here – Rob Jan 13 '17 at 02:25

2 Answers2

11

Read this blog post from Stephen Cleary:

Eliding Async and Await

Community
  • 1
  • 1
Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
7

No, you should not just add async to method without await - there is even compiler warning for it.

You also should not needlessly add await inside such method as it will make compiler to generate significantly more complicated code for the method with some related performance implications.

There is no observable difference between two patterns from timing point of view - task will still run asynchronously and you still be able to await immediately or at later point in caller.

There is one difference I can think of - if you return task directly caller may use ConfigureAwait(false) and it will finish on other thread. When you await that task inside you method that method controls where code after await is executed.

Note that cost of method with single await at the end is not significantly worse than one without - so if you prefer for coding style consistent usage of async on all asynchronous methods it is likely fine except rare time critical pieces.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    Another useful case for adding `async` and `await` is to wrap your code with a `try` block. Although a try block would compile in both cases, the behavior is VERY different. – Aron Jan 13 '17 at 02:17
  • @Aron makes sense in specific cases and error catching. For the Insert example I gave, I would probably try-catch higher up the callstack. – contactmatt Jan 13 '17 at 02:38
  • @contactmatt I disagree. I agree that the actual error "handling" should be done further up the stack. However, this is the correct place to enrich the exception. In your case I would catch `SqlException` and wrap-rethrow the with more application specific exception. – Aron Jan 13 '17 at 02:50
  • One difference: if it doesn't await it, the method returning the task won't appear in the async callstack if an exception is thrown by the downstream asynchronous method (ie. if the task fails) – Richard Szalay Jan 13 '17 at 10:36