0

I have a async method returning a task. Do I need to return anything in the following situation?

    public async Task UpdateProductSpecificationsAsync()
    {
        await _productRepository.UpdateProductSpecificationsAsync(); //Takes long time to execute
    }

Is the following code examples equivalent to each other?

    public Task UpdateProductSpecifications()
    {
        _productRepository.UpdateProductSpecifications(); //Takes long time to execute
        return Task.FromResult(0);
    }

    public Task UpdateProductSpecifications()
    {
        _productRepository.UpdateProductSpecifications(); //Takes long time to execute
        return Task.CompletedTask;
    }

Is there any situation where I should await a Task.TaskCompleted?

Jonas
  • 3,155
  • 5
  • 35
  • 55
  • 3
    Well it's not achieving anything asynchronously-wise, may as well be synchronous –  Aug 14 '17 at 13:47
  • What if the UpdateProductSpecifications function takes long time to execute and need to run simultaneously for different products? It can also be beneficial to release resources on the calling side while UpdateProductSpecifications function is executing. – Jonas Aug 14 '17 at 13:50
  • How would you know when the update completed in the 2nd example? – Kenneth K. Aug 14 '17 at 14:07
  • 1
    Just wrapping it a method that returns a **Task** and that performs a **Task.FromResult** doesn't magically make the end result async. Your thread is still going to **block**! You should be using await/async all the way. If anything you could use **Task.Run()** however your code is I/O bound so it's not recommended. In your case consider using async database calls and await them –  Aug 14 '17 at 14:10
  • an `async` method is executed synchronously until the first `await`, meaning your methods are still synchronous. I think that is what MickyD referred to. Your method `UpdateProductSpecificationsAsync` is currently executed synchronously – default Aug 14 '17 at 14:10
  • @JonasAxelsson What are you trying to achieve here, why aren't you using an asynchronous update instead? – johnny 5 Aug 14 '17 at 16:21
  • @KennethK. Just a bad example, in production we of course need to know if the update succeded. – Jonas Aug 15 '17 at 06:23
  • @Default I have updated the methodname in the code examples to clarify that the method isn't running a asynchronously. – Jonas Aug 15 '17 at 06:26
  • @johnny5 The first code example is using an asynchronous update in the database. The other example can be ignored since as other point out, the update is running synchronously, wrapping the update in a Task method does'nt help. – Jonas Aug 15 '17 at 06:29

1 Answers1

4

I have a async method returning a task. Do I need to return anything in the following situation?

An async Task method is equivalent to a non-async void method. And like a non-async void method, an async Task method can't return anything.

That said, your example seems odd. If all you're going to do in the method is await some other async method, you should not bother with the async/await at all. Just return the Task directly:

public Task UpdateProductSpecificationsAsync()
{
    return _productRepository.UpdateProductSpecificationsAsync();
}

Is the following code examples equivalent to each other?

Define "equivalent". To me, they are definitely not equivalent. The first creates a new Task<int> object, and returns that object as a Task. Calling code would have to cast it back to Task<int> to see the result value.

The second returns the static Task.CompletedTask property value, which is a singleton object, allocated only once per process. There is no result value for the caller to read.

The caller would have to go to extra work to directly observe those differences, but at the very least, returning a reference to a singleton object is more efficient than creating a new object every time. Whether this is significant or not depends, of course, on how often you call the method.

All that said, I don't understand why in that scenario, you wouldn't implement it like this (assuming there's no truly asynchronous version of the _productRepository method):

public Task UpdateProductSpecificationsAsync()
{
    return Task.Run(() => _productRepository.UpdateProductSpecifications());
}

Then you'd get actual asynchronous behavior, which is what the caller would typically expect. Your versions force the caller to wait in spite of the method looking like it's asynchronous. IMHO, it's a very bad idea to write code that lies.

Is there any situation where I should await a Task.TaskCompleted [sic]?

You mean directly? Or by code that doesn't know it's been handed the Task.CompletedTask reference? I'm going to assume the former, because it's unreasonable to expect the latter to have any idea that's what it's doing.

That seems like an overly broad question to me. Any situation? That's open to interpretation.

That said, I would say "no" to that question. What would the point of awaiting something you know is already completed? The await won't yield back to the caller, because the awaitable is already completed. It seems like a waste to me.

I can imagine scenarios where one awaits a Task.CompletedTask in order to achieve some other desired side-effect. I've seen weirder things than that in production code. But I wouldn't recommend it. Whatever hypothetical side-effect we'd be talking about, I'm sure it's not a documented side-effect, so one would be relying on undocumented implementation details that could change in the future.

Don't write fragile code. Write code that relies only on documented behavior, and only does things that make obvious sense. (And the corollary: if you break that rule, at the very least write a very detailed comment explaining why you wrote weird, fragile code.)

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136