在没有等待的情况下使用async的最佳做法是什么?

时间:2015-02-10 11:02:31

标签: c# .net multithreading asynchronous async-await

应用

我有一个由多个项目引用的View ModelViews

由于API,部分View项目为async而其他项目则不是。{/ p>

View项目使用IOC容器将其实现的接口注入View Model

代码

考虑这个代码的最小例子

界面:

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

View Model等待GetData方法:

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项目使用Async函数获取数据

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

Synchronous View项目使用同步调用来获取数据,但由于接口的约束,我需要返回一个Task,但我只对返回Data感兴趣使方法异步。

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

但是然后会发出警告:

  

这种异步方法缺少'await'运算符并将同步运行。考虑使用'await'运算符等待非阻塞API调用,或'await Task.Run(...)'在后台线程上执行CPU绑定工作。

这对我很好,因为我不在乎它是否同步运行。

使用Task.Run来抑制警告似乎是不必要的,因为调用可以(在我的情况下)来自后台线程。

问题

是否有最佳实践来实现此类非等待异步方法?可以忽略警告吗?有没有更好的方法来实现 async 同步调用?

其他

我确实将界面转换为同步调用,并使用Task.Result中的Asynchronous View(修复了警告),但这导致应用停止响应并出现了很多难题

注意:我声明使用async关键字神奇地使该方法异步运行。

3 个答案:

答案 0 :(得分:9)

async是一个实现细节,因此如果您不使用await,可以将其从方法中删除,然后您可以使用Task.FromResult返回已完成的任务并获得所需的结果

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

答案 1 :(得分:5)

  

是否有最佳实践来实现此类非等待异步方法?

是的,它称为同步API 。不要强迫那些自然不同步的代码。添加GetData方法,该方法返回string

  

可以忽略警告吗?

只要您了解其含义,

确定。调用可能从异步方法长时间运行的同步方法可能会让这个方法的消费者感到惊讶,因为它实际上会阻塞。 此外,还有一个事实是,任何异常都将通过生成的{ - 1}}状态机进行封装。当然还有状态机本身和任何解除操作员的小开销。

  

有没有更好的方法来实现异步同步调用?

这实际上取决于用例。如果这是一个不明显的简短操作,您可以使用Task并删除Task.FromResult修饰符(如其他人所说)或将调用推迟到线程池线程。从你的问题我明白你也不想要。

答案 2 :(得分:3)

您的界面应实现两种不同的方法,让调用者决定是否需要异步或同步

Data GetData();

Task<Data> GetDataAsync();

这是运行异步方法synchron的可能方法

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

        throw getDataTask.Exception;
    } 
}