释放主线程的占用,提高吞吐量,直接运行并不能提高速度,合适场景使用,当然全部都写异步也并没大问题,只是代码难提升了,建议合适场景使用,高并发,数据库请求时间过长等场景使用
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=2349db.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
SqlSugarClient和SqlSugarScope都能用 (SqlSugarClient模式推荐用CreateScope)
db.CopyNew().Queryable<T>().ToListAsync()
只支持SqlSugarClient 也是SqlSugarClient推荐用法
使用教程:https://www.donet5.com/Ask/9/35795
2016 © donet5.comApache Licence 2.0