1

.Net 4.6

What is the difference between calling method with await that has "async" and the same that doesn't have "async" or is there any difference?

protected Task<MyObject<T>> MyMethod1<T>(string parameter)
{
    return CallDb();
}

protected async Task<MyObject<T>> MyMethod2<T>(string parameter)
{
    return await CallDb();
}

// Calling these
public async Task<IEnumerable<string>>(string parameter)
{
    return await MyMethod1<string>(parameter);
    // Any difference?
    return await MyMethod2<string>(parameter);
}

public Task<string> CallDb()
{
}
st_stefanov
  • 1,147
  • 1
  • 10
  • 28
  • show the definition for `CallDb()` – jazb Jul 24 '19 at 07:22
  • It depands on what `CallDb` is – slow Jul 24 '19 at 07:23
  • Ok, here it is. – st_stefanov Jul 24 '19 at 07:24
  • 3
    Possible duplicate of [this](https://stackoverflow.com/questions/19098143/what-is-the-purpose-of-return-await-in-c). TL;DR The compiler will generate a redundant state machine for MyMethod2 in this case. – StuartLC Jul 24 '19 at 07:24
  • Not really duplicate, because mine always returns "await". – st_stefanov Jul 24 '19 at 07:25
  • 2
    on the requests to show `CallDb` - neither the compiler nor the runtime will care about what `CallDb` looks like, so IMO neither should we. The only interesting question at runtime is: "does `CallDb` always complete synchronously, despite advertising as `Task`?". Two additional notes: 1) prefer `ValueTask[]` over `Task[T]` **always** IMO (even when it will always be async... dammit I need to finish my blog post on that!), and 2) note that `Task>` might not behave in the way you want; when .NET Core 3 lands, prefer `IAsyncEnumerable` – Marc Gravell Jul 24 '19 at 07:34
  • Possible duplicate of [What is the purpose of "return await" in C#?](https://stackoverflow.com/questions/19098143/what-is-the-purpose-of-return-await-in-c) – JSteward Jul 24 '19 at 17:12

3 Answers3

6

If you're talking about the difference between MyMethod1 and MyMethod2, then in this exact scenario the only difference is that MyMethod2 has slightly more overhead and some very subtle differences in how exceptions would be raised (in terms of who gets blamed). In particular, MyMethod2 will end up allocating an extra task, and will have some extra async-state-machine boilerplate, which may also end up being boxed and going onto the heap if CallDb turns out to be incomplete.

In general, if you don't need to do anything extra (pre/post-processing of values, using, finally, etc), I would recommend MyMethod1 - i.e. don't introduce the async machinery without a reason.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I agree, particular on the last thing. Multitasking is a huge headache. A headache you really want to avoid if you do not actually need it. – Christopher Jul 24 '19 at 07:29
  • @Christopher well, maybe, but you're not adding to, or avoiding, anything "multitasking" related when choosing between `MyMethod1` and `MyMethod2`; the concurrency is identical there – Marc Gravell Jul 24 '19 at 07:29
1

In the await call, the task is being executed and awaited. This causes quite a lot of things to happen. Often the context is captured, sometimes a thread spun up and Stephen can tell you more about that.

If you just return a Task, its up to the caller to await it (or just leave it).

If you have nested awaits, this causes extra overhead. So, if not necessary dont use an await but return the Task where possible.

Stefan
  • 17,448
  • 11
  • 60
  • 79
  • "If you just return a Task, nothing starts yet. You just have a definition of what you are going to to. Its then up to the caller to await it (or just run it)." - I don't think that sentence applies here at all; whatever starts or doesn't start will be identical - the only difference here is in the extra wrapper plumbing code - the state machine code – Marc Gravell Jul 24 '19 at 07:29
  • Ehjhmmm... yes, thats true... let me fix that. – Stefan Jul 24 '19 at 07:36
  • @MarcGravell: that should fix it. – Stefan Jul 24 '19 at 07:39
0

What is the difference between calling method with await that has "async" and the same that doesn't have "async" or is there any difference?

There's no difference in calling those methods at all. At runtime, both methods just return a Task<T>. await consumes an awaitable (usually a task); it doesn't matter where that task comes from. async is an implementation detail.

There's a difference in the implementation of those methods, but that's covered in this question.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810