需要满足下面2条
1、 你想要最快的执行完,并且不在乎短期占用太多资源,能保证线程安全(比Task.Run 性能更快,也不需要考虑线程安全)
2、 数据库操作10个以上,如果只有几个数据库操作就没必要用了和一般的异步没多少区别
注意:每种数据库用法不一样
Task并行执行数量在100以下为佳,如果超过100需要设置max pool size=1000,
并且建议并行执行一次不要超1000 (如果是SqlServer用法2性能更好)
var ts = new List<Task>();
for (int i = 0; i < 1000; i++)//建议一次执行Task不工
{
//需要CopyNew()强制new出新对象,因为AsyncLocal没办法区分异步上下文
ts.Add(db.CopyNew().Queryable<Order>().FirstAsync());
}
await Task.WhenAll(ts);
//如果用db.CopyNew().XXX.ToListAsync()这种不需要包Task.Run
//db.ThenMapper异步并发需要这样处理
var ts = new List<Task>();
for (int i = 0; i < 1000; i++)//建议一次执行Task不工
{
var newDb=db.CopyNew();
var list=await newDb.Queryable....;
ts.Add(newDb.ThenMapperAsync...)
}
await Task.WhenAll(ts);注意:1、异步方法 Task.WhenAll
2、db是同一个,并且用事务
3、SqlServer需要连接字符串加上 MultipleActiveResultSets=True
4、Thenmapper 要按标题1来实现
下面是一个完整的用例并且测试通过
using System.Linq;
using System.Threading.Tasks;
namespace OrmTest
{
class Program
{
static async Task Main(string[] args)
{
int max = 1000;
Task[] tasks = new Task[max];
var db = GetClient();//db需要是同一个
db.BeginTran(); //强制关闭自动释放(如果手动释放可以不用事务)
for (int i = 0; i < max; i++)
{
//如果是SqlSugarScope禁止出现Task.Run
//原因:有Task.Run SqlSugarScope异步上下文会变事务会有问题
tasks[i]=db.Queryable<Order>()
.Take(10)
.ToListAsync();//直接等于ORM异步方法
}
await Task.WhenAll(tasks);
db.CommitTran(); //关闭数据库
}
private static SqlSugarClient GetClient() //SqlSugarClient和SqlSugarScope都行
{
return new SqlSugarClient(new ConnectionConfig()
{
DbType = SqlSugar.DbType.SqlServer, //SqlServer Sqlite Oracle
//注意配置
ConnectionString = OrmTest.Config.ConnectionString,
IsAutoCloseConnection = true,
AopEvents = new AopEvents
{
OnLogExecuting = (sql, p) =>
{
Console.WriteLine(sql);
Console.WriteLine(string.Join(",", p?.
Select(it => it.ParameterName + ":" + it.Value)));
}
}
});
}
}
}测试结果
本身IIS就是多线程操作,所以不是特殊需求没必要并发查询,并发查询会把数据库的IO充份利用,并且可以保证线程安全,
| 配置 1165G7 SSD | 结果 |
Task.WhenAll | 1000个1秒 |
| Task.Run(()=>{ var db=new sqlsugarclient(); db.xxx}) | 1000就10秒 |
2016 © donet5.comApache Licence 2.0