C# 异步表达式

C# 异步表达式,c#,C#,我正在尝试使用一些方法生成一个存储库,包括这些方法的异步版本,如下所示: //Method 1 public static List<MyEntity> GetMyEntityByDate(MyContextType context) { var tmpMov = context.MyEntity .AsNoTracking() .ToList(); return tmpMov;

我正在尝试使用一些方法生成一个存储库,包括这些方法的异步版本,如下所示:

    //Method 1
    public static List<MyEntity> GetMyEntityByDate(MyContextType context)
    {
        var tmpMov = context.MyEntity
            .AsNoTracking()
            .ToList();

        return tmpMov; 

    }

    //Method 2 V1
    public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context)
    {
        var tmpMov = await context.MyEntity
            .AsNoTracking()
            .ToListAsync();

        return tmpMov; 
    }

    //Method 2 V2
    public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context)
    {
        List<MyEntity> tmpMov = null;  
        await Task.Factory.StartNew(() => { 
            tmpMov = GetMyEntityByDate(context);
        });

        return tmpMov; 
    }
现在我有一些问题:

就性能和流利性而言,使用Method2V1和Method2V2的优缺点是什么

在有人否决这个问题之前,是的,我正在实现一个存储库模式,希望编写更少的代码,这就是为什么我要考虑V2,这样我只有一个查询需要维护

但是我在异步方面的经验很差,显然我的目标是获得尽可能好的性能。

使用context.MyEntity.ToList使当前线程保持忙碌,直到数据库完成查询执行

使用wait context.MyEntity.toListSync;释放当前线程,直到数据库完成查询执行

使用wait Task.Factory.StartNew=>{};释放当前线程,但创建一个新线程,并使其处于忙碌状态,直到数据库完成执行。

使用context.MyEntity.ToList使当前线程处于忙碌状态,直到数据库完成查询执行

使用wait context.MyEntity.toListSync;释放当前线程,直到数据库完成查询执行

使用wait Task.Factory.StartNew=>{};释放当前线程,但创建一个新线程,并使其保持忙碌状态,直到DB完成执行

就性能和流利性而言,使用Method2V1和Method2V2的优缺点是什么

方法2V1是一种合适的异步方法。方法2 V2是一个伪异步方法,它在TaskScheduler.Current上执行阻塞工作,如果没有当前任务调度器,它将是线程池

因此,V2与最佳实践相冲突

在有人否决这个问题之前,是的,我正在实现一个存储库模式,希望编写更少的代码,这就是为什么我要考虑V2,这样我只有一个查询需要维护

我想说的是,理想的情况是实际上只公开方法2v1,而完全摆脱方法1。查询数据库本质上是基于I/O的,因此API自然是异步的

如果您确实需要同步和异步API,那么我建议使用

这可能看起来像:

private async static Task<List<MyEntity>> DoGetMyEntityByDateAsync(MyContextType context, bool sync)
{
  var query = context.MyEntity
      .AsNoTracking();
  return sync ?
      query.ToList() :
      await query.ToListAsync();
}

public static Task<List<MyEntity>> GetMyEntityByDateAsync(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: false);
}

public static List<MyEntity> GetMyEntityByDate(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: true).GetAwaiter().GetResult();
}
就性能和流利性而言,使用Method2V1和Method2V2的优缺点是什么

方法2V1是一种合适的异步方法。方法2 V2是一个伪异步方法,它在TaskScheduler.Current上执行阻塞工作,如果没有当前任务调度器,它将是线程池

因此,V2与最佳实践相冲突

在有人否决这个问题之前,是的,我正在实现一个存储库模式,希望编写更少的代码,这就是为什么我要考虑V2,这样我只有一个查询需要维护

我想说的是,理想的情况是实际上只公开方法2v1,而完全摆脱方法1。查询数据库本质上是基于I/O的,因此API自然是异步的

如果您确实需要同步和异步API,那么我建议使用

这可能看起来像:

private async static Task<List<MyEntity>> DoGetMyEntityByDateAsync(MyContextType context, bool sync)
{
  var query = context.MyEntity
      .AsNoTracking();
  return sync ?
      query.ToList() :
      await query.ToListAsync();
}

public static Task<List<MyEntity>> GetMyEntityByDateAsync(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: false);
}

public static List<MyEntity> GetMyEntityByDate(MyContextType context)
{
  return DoGetMyEntityByDateAsync(context, sync: true).GetAwaiter().GetResult();
}

由于ToListSync,V1在进行数据库查询时将利用异步IO,而V2不会,因此实际上不会使用async plus的任何优点,因为它会在等待响应时阻塞线程池线程,而不会产生任何结果。简而言之,忘记V2,使用V1。首先是一种同步方式,在第二种方式中,您只异步转换为列表,不会产生任何显著的增益,在2v2中,它被称为异步超过同步,最好使用Task.FromResult而不是Task.Factory.startnew由于ToListSync的原因,性能最好的V1在进行数据库查询时会利用异步IO,而V2不会,因此实际上不会使用async plus的任何好处,它会在等待响应时阻塞线程池线程,而不会产生任何后果。简而言之,忘记V2,使用V1。首先是一种同步方式,在第二种方式中,您只异步转换为列表,不会产生任何显著的增益,在2v2中,它被称为异步超过同步,使用Task.FromResult比使用Task.Factory.startnew更好,因为它具有尽可能好的性能,对您来说,最好的方法是什么?//我认为方法2 V1是最好的选择。我还在我的应用程序中实现这个模式well@JuanPabloGomez-我建议您在ToListSync或库调用中异步的任何其他部分之后添加.ConfigureWaitFalse。这将提高调用的效率,并指示回调不必在发起调用的线程上重新加入。因此,在这样的库上下文中,添加它是一件好事。不要在需要线程上下文的情况下使用它,如Mvc或Web api控制器的操作方法。如果可能,最好在外部服务(如DB查询、REST服务、磁盘IO等)执行进程时使用async/wait。类似于餐厅的服务员:它可以点菜并在餐桌旁等待,直到
它的准备好的同步方式,或者它可以接受您的订单,而当它准备好时,它会去接受其他客户的订单以及异步方式您忘了提到在单独的任务中运行同步方法是一种称为async over sync的反模式,这不是推荐的方式。如果某个类或库提供异步方式来运行操作,那么最好使用它,因为它在较低级别上是异步的。对您来说,什么是最好的方式?//我认为方法2 V1是最好的选择。我还在我的应用程序中实现这个模式well@JuanPabloGomez-我建议您在ToListSync或库调用中异步的任何其他部分之后添加.ConfigureWaitFalse。这将提高调用的效率,并指示回调不必在发起调用的线程上重新加入。因此,在这样的库上下文中,添加它是一件好事。不要在需要线程上下文的情况下使用它,如Mvc或Web api控制器的操作方法。如果可能,最好在外部服务(如DB查询、REST服务、,磁盘IO等类似于餐厅的服务员:它可以接受订单并在您的餐桌旁等待,直到其准备好同步方式,或者它可以接受您的订单,并且在其准备好时,它以异步方式从其他客户那里获取订单。您忘记了在单独的任务中运行同步方法是一种称为async over sync的反模式,不推荐使用这种方式。如果某个类或库提供异步方式来运行操作,那么最好使用它,因为它在较低级别上是异步的。