Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best practice using async without await? [duplicate]

Application

I have a View Model that is referenced by multiple projects or Views.

Due to the API, some of the View projects are async and others are not.

The View project injects it's implementation of an interface into the View Model using an IOC container.

Code

Consider this minimal example of the code

The interface:

public interface IDatabase
{
    Task<Data> GetData();
}

The View Model awaits the GetData method:

public class DisplayDataViewModel
{
     private readonly  IDatabase _database
     public DisplayDataViewModel(IDatabase database)
     {
          _database = database;
     }

     private async Task GetDataFromDatabase()
     {
         Data data = await _database.GetData();
         // do something with data...
     }
}

Asynchronous View project uses an Async function to get the data

public class AsynchronousViewDataBase : IDatabase
{
    public async Task<Data> GetData()
    {
        return await GetDataAsync();
    }
}

Synchronous View project uses a synchronous call to get the data, but due to the constraint of the interface, I need to return a Task, but I am merely interested in the return of the Data thus making the method async.

public class SynchronousViewDatabase : IDatabase
{
    public async Task<Data> GetData()
    {
        return GetData();
    } 
}

But then it gives warning:

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Which is sort-of fine with me, since I don't care if it runs synchronously.

Using a Task.Run to suppress the warning seems unnecessary since the call can (and in my case does) originate from a background thread.

Question

Is there a best practice to implement this type of non-await async method? Is it okay to ignore the warning? Is there a better way to implement the async Synchronous call?

Additional

I did convert the interface to a synchronous call, and using the Task.Result in the Asynchronous View (which fixed the warning), but that caused the app to stop responding and just a lot of difficult issues.

Note: I am not stating that using the async keyword magically makes the method run asynchronously.

like image 796
Barnstokkr Avatar asked Feb 10 '15 11:02

Barnstokkr


People also ask

Should I use async without await?

Marking a function as async without using await or returning a value inside it can lead to an unintended promise return and a larger transpiled output. Often the function can be synchronous and the async keyword is there by mistake.

What happens if async method is called without await?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

Which is the best standard approach on error handling for async function?

Error handlingA try/catch block can be used to handle asynchronous errors in an async function. Alluding to the fact that an async function always return a Promise, one can opt to use a . catch() in place of a whole try/catch block.


3 Answers

async is an implementation detail so you can remove it from the method if you are not using await, then you can use Task.FromResult to return an already completed task with the required result.

public class SynchronousViewDatabase : IDatabase
{
    public Task<Data> GetData()
    {
        return Task.FromResult<Data>(GetData());
    } 
}
like image 170
NeddySpaghetti Avatar answered Nov 15 '22 17:11

NeddySpaghetti


Is there a best practice to implement this type of non-await async method?

Yes, its called a synchronous API. Don't force code which isn't naturally async to be so. Add a GetData method which returns a string.

Is it okay to ignore the warning?

It's ok as long as you understand the implications. Calling a synchronous method which may be long running from an async method will probably surprise the consumers of this method as it will actually block. Also, there's the fact that any exception will be encapsulated via the state-machines generated Task. And of course the small overhead of the state machine itself and any lifted operators.

Is there a better way to implement the async Synchronous call?

It really depends on the use-case. If this was a short operation which isn't noticeable, you can get away with using Task.FromResult and removing the async modifier (as others said) or deferring the call to a thread pool thread. From your question i understand you want neither.

like image 26
Yuval Itzchakov Avatar answered Nov 15 '22 18:11

Yuval Itzchakov


Your interface should implement two different Methods and let the caller decide if he needs it async or sync

Data GetData();

and

Task<Data> GetDataAsync();

here is a possible way to run your async method synchron

public class SynchronousViewDatabase : IDatabase
{
    public Data GetData()
    {
        var getDataTask = GetDataAsync();
        getDataTask.RunSynchroniously();
        if(getDataTask.Status == TaskStatus.RanToCompletion)
           return getDataTask.Result;

        throw getDataTask.Exception;
    } 
}
like image 21
BoeseB Avatar answered Nov 15 '22 19:11

BoeseB