程序员的知识教程库

网站首页 > 教程分享 正文

巧用ThreadPool.QueueUserWorkItem实现接口二次调用

henian88 2024-08-15 05:07:03 教程分享 21 ℃ 0 评论

背景

最近做了个项目有个接口涉及到批量计算的问题,耗时比较长。大家都知道,接口等待时间太长肯定是不可取的。那么只能做异步处理了;但是问题来了这个项目没有什么消息队列、redis之类的使用,本着怎么简单怎么来的思路,新搞个消息队列不现实;这时候,多线程派上用场。

再次遇到问题

于是噼里啪啦写了一顿,发现有个问题,我的方法涉及到很多ef core 数据库操作,在多线程的条件下,

报错如下:System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913

生命周期为Scope方式,随着请求的结束,实例生命周期也会被释放,因此在多线程下若共享实例,容易出现实例已释放的错误,报错如下:Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.Autofac at Autofac.Core.Lifetime.LifetimeScope.BeginLifetimeScope(Object tag)。通过注入IServiceProvider,

就是这种方式也是不行的,还是需要改到原来的代码,还是违背初衷。

峰回路转

本来一筹莫展的,突然想到既然接口一次太慢了,那就分2次执行,第二次可以使用多线程触发,自己调用自己的耗时接口,这样就不需要改到原来的底层逻辑,要做的仅仅是把自己的方法拆分成2个。

1、请求一个异步方法,然后接口直接返回

 /// <summary>
/// 批量 添加 一级指标 数据(74.22分,全省第10名)
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
[HttpPost]
[Route("adminaddAreadatabatch")]
public bool addAreadatabatch(List<AreadataDto> entity)
{
// foreach (var item in entity ?? new List<AreadataDto>())
// {
// try
// {
_chartBll.Addbat(entity);
// }
// catch (Exception ex)
// {
// _logger.Error(ex);
// }
// }
`
ThreadPool.QueueUserWorkItem(new WaitCallback(InsertNewsInfoExt), JsonConvert.SerializeObject(entity));`

return true;
}

2、这里做一个http请求

 private void InsertNewsInfoExt(object info)
{
var client = new RestClient("http://xxxx/api/ningdeChart/updateAreadata");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
var body = info.ToString();
request.AddParameter("application/json", body, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}


3、在原来的接口adminaddAreadatabatch做下二次拆分,提供一个新的api

 [HttpPost]
[Route("updateAreadata")]
public bool updateAreadata(List<AreadataDto> entity)
{
foreach (var item in entity ?? new List<AreadataDto>())
{
try
{
_logger.Info("updateAreadata");
_chartBll.updateAreadata(item.areaid, item.t1);
}
catch (Exception ex)
{
_logger.Error(ex);
}
}
return true;
}

问题得到解决。


本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表