我正在尝试使用某些方法生成存储库,并包括这些方法的异步版本,如下所示:
//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;
}
现在我有一些问题:
就性能和流利度而言,使用Method 2 V1 vs Method2 V2有什么优缺点?
在有人否决这个问题之前,是的,我正在实现一个存储库模式,并希望编写更少的代码,这就是为什么我考虑使用V2,这样我只需要维护一个查询。
但是我在异步方面经验不足,因此我的目标是尽可能获得最佳性能。
最佳答案
就性能和流利度而言,使用Method 2 V1 vs Method2 V2有什么优缺点?
方法2 V1是适当的异步方法。方法2 V2是伪异步方法,该方法在TaskScheduler.Current
上执行阻塞工作(如果没有当前的任务调度程序,则该线程为线程池)。
因此,V2违反了最佳实践not to expose asynchronous wrappers for synchronous methods。
在有人否决这个问题之前,是的,我正在实现一个存储库模式,并希望编写更少的代码,这就是为什么我考虑使用V2,这样我只需要维护一个查询。
我想说的理想情况是实际上只公开方法2 V1,并完全摆脱方法1。查询数据库本质上是基于I / O的,因此该API自然是异步的。
如果确实需要同步和异步API,则建议使用"bool argument hack" as described in my MSDN article on Brownfield Async Development。
可能看起来像:
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();
}
关于c# - 异步表达式C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39641884/