释放主线程的占用,提高吞吐量,直接运行并不能提高速度,合适场景使用,当然全部都写异步也并没大问题,只是代码难提升了,建议合适场景使用,高并发,数据库请求时间过长等场景使用
async void 和 async Task的区别:
Task类型返回值有等待效果,既能保证线程安全又不会堵塞主线程,是推荐的用法。
void没有等待效果,需要考虑线程安全,例如使用 db.CopyNew() 来保证。
对于表达式也有 Action 和 Func<Task>,其中 Action 等同于 void,Func<Task> 等同于 Task。
List.ForEach 是一个 Action,所以 async 不会等待。可以替换为 foreach(var item in list)。
SqlSugar中ToList是同步方法,那么ToListAsync这种是异步方法,通过Async来区别是同步还是异步方法
2.1 返回类型只能是Task或者Task<类型>
2.2 只要用到异步方法必须加上await
Public void GetAll(){ 异步方法 }//错误 (方法要有Task返回值) Public async Task GetAll(){ 异步方法 }//错误 (缺少await) Public async void GetAll(){ await 异步方法 }//错误 (方法要有Task返回值) Public async Task GetAll(){ await 异步方法 }//正确 Public async Task<T> GetAll(){ await 异步方法 return xxx; }//正确 //异步表达式需要看类型是不是Task否则禁止用异步 Action a= async ()=> await 异步方法 //错误 (Action等于Void不是Task) Func<Task> a= async()=> await 异步方法 //正确 Parallel.Foreach(Action action) //错误 不是异步委托 (Action等于Void不是Task) List.Forech(Action action) // 错误 不是异步委托 (Action等于Void不是Task) public Task TestAsync()//正确 forach是C#语法不是函数所以和委托没关系 { foreach(var item in list) { await 异步方法 } } public Task TestAsync()//错误用法 { Task.Run(()=>{ 异步方法 }) } public void TestAsync()//正确用法 唯一一种 返回值不是Task 异步用法 { Task.Run(async ()=>{ //如果是 SqlSugarClinet需要new await异步方法 }) } public Task TestAsync()//正确用法 { await Task.Run(async ()=>{ await异步方法 }) }
用例:
var data=await db.Queryable<Order>().FirstAsync(); var list= await db.Queryable<Order>().Where(it=>it.Id==1).ToListAsync(); //分页需要特别注意用法 RefAsync<int> total = 0; var list=await Db.Queryable<Order>().ToPageListAsync(1, 2, total);
如果是异步方法必须全部加上Await , 如果漏掉不写就会出现偶发性错误
//正确用法 每个异步方法都用await进行串起来 public async Task<List<Order>> Test() { var db = GetInstance(); await GetAsync(); await db.Queryable<OrderItem>().ToListAsync(); return await db.Queryable<Order>().ToListAsync(); } //错误用法,异步中禁止用sleep Thread.Sleep(1) //正确用法 await Task.Delay(1) //只能写到异步方法后面 //需要注意的用法 await Task.WhenAll //看文档 https://www.donet5.com/Home/Doc?typeId=2349
db.Ado.CancellationToken = token; List<Order> list1 =await db.Queryable<Order>().ToListAsync(); List<Order> list2 =await db.Queryable<Order>().ToListAsync(); db.Ado.RemoveCancellationToken();
The connection does not support MultipleActiveResultSets
(1)、SqlSugarClient 替换成 SqlSugarScope ,因为SqlSugarScope 是线程安全对象代码容错率高
具体用法: https://www.donet5.com/Home/Doc?typeId=1181
(2) 、异步用法错引起的 ,排查没用Await调用的异步方法 ,正确用法看当前文档2
Parallel.ForEach 只能使用同步方法,不能使用异步方法
//参数2是一个 Action 而不是Func<Task> 所以是不支持异步表达式的 public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body);
请使用Task.WhenAll替换Parallel 具体用法如下:
https://www.donet5.com/Home/Doc?typeId=2349
有些情况必须强一个新对象出来保证线程安全,SqlSugarScope也需要这样处理
注意:没有await一定要加CopyNew (SqlSugarScope也要加)
因为db对象是不支持跨上下文使用,直接写异步不加await 就会出现在不上下文使用db
这个时候用 db.Copynew() 就能实现强制new一个新的SqlSugarClient
//方式1:2种方式都必须加CopyNew() db.CopyNew().Queryable<T>().ToListAsync() //事务var mydb=db.CopyNew() db.CopyNew().Queryable<T>().ToListAsync()
db.CopyNew().Queryable<T>().ToListAsync()
db.CopyNew().Queryable<T>().ToListAsync()
就这几种情况必须要加db.CopyNew(),其他只要用法正确都OK
2016 © donet5.comApache Licence 2.0