通过多线程(任务)运行方法的有效方法[重复]
Posted
技术标签:
【中文标题】通过多线程(任务)运行方法的有效方法[重复]【英文标题】:Efficient way to run method by multiple thread(task) [duplicate] 【发布时间】:2021-02-21 01:41:10 【问题描述】:我正在寻找使用多线程运行方法的最佳方式。
这是我想运行的方法
public async Task<IActionResult> GenerateById(int id)
//make a web request and save response to database using EF.
return Json(new success = true, message = "Worked" );
我需要为 ID 1 到 40 运行此方法,目前,它由 hangfire 完成,有 10 个作业。
在startup.cs中
recurringJobManager.AddOrUpdate("GenerateAll1",
() => serviceProvider.GetService<IGenerator>().GenerateAll(1), "0 * * * *");
recurringJobManager.AddOrUpdate("GenerateAll2",
() => serviceProvider.GetService<IGenerator>().GenerateAll(2), "0 * * * *");
recurringJobManager.AddOrUpdate("GenerateAll3",
() => serviceProvider.GetService<IGenerator>().GenerateAll(3), "0 * * * *");
....
recurringJobManager.AddOrUpdate("GenerateAll10",
() => serviceProvider.GetService<IGenerator>().GenerateAll(10), "0 * * * *");
这是GenerateAll
public async Task GenerateAll(int mod)
if (mod == 10)
mod = 0;
List<DataSetting> listsToUpdate = _unitOfWork.DataSetting.GetAll(r => r.Id%10 == mod ).ToList();
foreach (var list in listsToUpdate )
await GenerateById(list.Id);
所以每个作业处理 4 个 id(例如 ..GenerateAll1 为 Id 1、11、21 和 31 运行) 但我发现这是低效的。 因为当 GenerateById(11) 需要很长时间时,即使 GenerateAll2 作业已经完成,GenerateById(21) 和 GenerateById(31) 也不会运行,直到 GenerateById(11) 完成。
我想做的是像hangfire一样只运行1个工作
recurringJobManager.AddOrUpdate(
"GenerateAll1",
() => serviceProvider.GetService<IGenerator>().GenerateAll(), "0 * * * *");
GeneratAll() 方法创建 10 个线程,每个线程获取 Id 并运行 GenerateById 方法。 完成后,它会使用尚未生成的 id 运行 GenerateById。 所以所有 10 个线程都在工作,直到生成所有数据设置。
我可以就这种情况获得任何建议吗?
谢谢
【问题讨论】:
为什么不为每个 id 创建一个Task
,一次启动它们,然后只使用 await
整个集合?我想,这里没必要乱搞线程。
像Parallel.For(0, 40, x => GenerateById(x));
这样的东西有用吗?
OP 需要提供更多信息。这是在 Asp.net 应用程序上吗?每个请求是否需要调用 `GenerateById(int id)` 40 次?等
【参考方案1】:
Parallel.For
对您尝试做的事情很有用。目前尚不清楚您对GenerateById()
的结果的意图是什么,所以我将把它留给您自己弄清楚。
来自文档:
执行一个 for 循环,其中迭代可以并行运行。
recurringJobManager.AddOrUpdate(
"GenerateAll1",
() => serviceProvider.GetService<IGenerator>().GenerateAll(), "0 * * * *");
public async Task GenerateAll()
Parallel.For(0, _unitOfWork.DataSetting.Length,
new ParallelOptions() MaxDegreeOfParallelism = 10 ,
x => GenerateById(_unitOfWork.DataSetting[x]).Result());
public async Task<IActionResult> GenerateById(int id)
...
return Json(new success = true, message = "Worked" );
【讨论】:
嗨,杰瑞,感谢您的建议。我应该提到方法 GenerateById()。它发出网络请求并将响应数据保存到数据库,所以它是由 EF 完成的。我得到一个错误,“在前一个操作完成之前,在这个上下文上开始了第二个操作”。您有什么想法可以与方法使用 EF 并行使用吗? 如果您希望所有线程访问同一个 DbContext 实例,那么您必须使用锁,这样一次只有一个线程在访问它。如果与您的网络请求相比,上下文的操作速度更快,那么并行执行此操作仍然会有很大的好处。以上是关于通过多线程(任务)运行方法的有效方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章
通过多线程分配 CoreLocation 和 CoreMotion 更新的最佳设计?