开发过程中,有时因为业务需求,需要我们执行完成正常的业务逻辑之后,再去做一些不影响主业务流程的操作。当我们的主流程已经完成了,没必要关注之后进行的操作的返回结果,这时我们就可以尝试开启一个新的线程来帮我们完成这个需求,让当前的线程不必因此而停滞等候。
1、Task.Run()的使用:
········public WebApiResult TestService()
{
var result = new WebApiResult();
try
{
// 执行主要业务流程,假设删除一条数据
Console.WriteLine("主要流程执行结束;");
// 调用外部接口通知某条数据已被删除,将此消息推送到消息队列
Task.Run(() => this.PushService());
}
catch (Exception ex)
{
result.AddError(this.GetException(ex));
}
return result;
}
public void PushService()
{
// 推送消息队列
// 此处不做详细介绍,感兴趣可自行百度消息队列的使用
}
public virtual string GetException(Exception ex)
{
var s = ex.Message;
if (ex.InnerException != null)
{
return s + "\n" + GetInnerException(ex.InnerException);
}
return s;
}
注:如果异步调用的方法中需要对数据库进行操作,需要开启一个新的数据库连接事务
2、借助Parallel.For()及 Parallel.ForEach()进行异步处理:
public WebApiResult<AdjustPriceDetailModel> GetAdjustPriceDetail(string adjustPriceId)
{
var result = new WebApiResult<AdjustPriceDetailModel>();
try
{
int count = 10;
List<string> list = new List<string>();
// 异步for循环,数据量大的情况下可加快执行效率
// 千万不要在次循环中往公用的集合中添加值,存在数据被覆盖的情况
Parallel.For(0, count, t =>
{
var num = t + 1;
//log.Info(num);
list.Add($"第{num}条数据");
});
log.Info($"输出:{JsonConvert.SerializeObject(list)}");
}
catch (Exception ex)
{
result.AddError(this.GetException(ex));
}
return result;
}
错误示范:
public WebApiResult<AdjustPriceDetailModel> GetAdjustPriceDetail(string adjustPriceId)
{
var result = new WebApiResult<AdjustPriceDetailModel>();
try
{
int count = 10000;
List<string> list = new List<string>();
// 异步for循环,数据量大的情况下可加快执行效率
// 千万不要在次循环中往公用的集合中添加值,存在数据被覆盖的情况
Parallel.For(0, count, t =>
{
var num = t + 1;
//log.Info(num);
list.Add($"第{num}条数据");
});
log.Info($"输出:{list.Count()}");
}
catch (Exception ex)
{
result.AddError(this.GetException(ex));
}
return result;
}
通过日志输出就能看出在数据量很大的情况下会出现数据呗覆盖的情况,因此如果在for循环中涉及到对公用变量的修改,不建议使用异步for循环
一千条数据情况下的日志输出
2020-03-01 15:20:35.1027 INFO 输出:1000
一万条数据情况下的日志输出
2020-03-01 15:21:08.4059 INFO 输出:6109
Parallel.ForEach()的用法跟 Parallel.For()的用法略有不同,但是基本一致,同样也存在数据覆盖的问题。
Parallel.ForEach(list, item =>
{
Console.WriteLine(item);
});
注意:数据量很大的情况下会出现数据呗覆盖的情况