[英]Using SemaphoreSlim for divide execution for batches
我正在从头开始学习异步编程,并且必须解决一个问题。 我正在开发的应用程序必须按 ID 循环下载数据(大约 800 次循环通过)。 每个 Loop 循环从数据库中获取 10 到 500 行,并生成一个包含行的 txt 文件。 我想异步执行此操作。 当然不想同时生成 800 个报告(800 个 sql 查询)但想将它分成几批。 我使用SemaphoreSlim
:
public async void Generate(DateTime BusinessDate)
{
var throttler = new SemaphoreSlim(5);
var allTasks = new List<Task>();
foreach (var id in idsToGenerate)
{
await throttler.WaitAsync();
allTasks.Add(Task.Run(async () =>
{
GenerateReportForIdAsync(id, BusinessDate);
}));
throttler.Release();
}
await Task.WhenAll(allTasks);
}
private Task GenerateReportForIdAsync(Id id, DateTime day)
{
return Task.Run(() => GenerateReportForOid(id, day));
}
private void GenerateReportForId(Id id, DateTime day)
{
LogInformation(); // shortcut
GetDataFromDB(); // shortcut
CreateReportFromRecordFromDB(); // shortcut
UpdateInformationInDBThatReportHasBeenGenerated(); // shortcut
}
此代码有效,因此已生成报告,但看起来方法UpdateInformationInDBThatReportHasBeenGenerated()
尚未针对最后 1-10 个报告运行(取决于执行)。 因此,对于某些记录,看起来应用程序在执行UpdateInformationInDBThatReportHasBeenGenerated()
之前已完成。
你知道为什么吗?
更新这是有效的:
public void Generate(DateTime BusinessDate)
{
var taskAsync = GenerateAsync(BusinessDate);
Task.WaitAll(taskAsync);
}
private async Task GenerateAsync(DateTime BusinessDate)
{
var ab = new ActionBlock<(Id id, DateTime businessDate)>(
GenerateReportForId,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5,
}
);
foreach (var id in idsToGenerate)
{
ab.Post((id, BusinessDate));
}
ab.Complete();
await ab.Completion;
}
private void GenerateReportForId((Id id, DateTime day) arg)
{
LogInformation(); // shortcut
GetDataFromDB(); // shortcut
CreateReportFromRecordFromDB(); // shortcut
UpdateInformationInDBThatReportHasBeenGenerated(); // shortcut
}
您可以使用来自Dataflow(任务并行库)的ActionBlock<TInput> Class轻松做到这一点:
public async Task Generate(DateTime BusinessDate)
{
var ab = new ActionBlock<(Id id, DateTime businessDate)>(
GenerateReportForId,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5,
}
);
foreach (var id in idsToGenerate)
{
ab.Post((id, BusinessDate));
}
ab.Complete();
await ab.Completion;
}
private void GenerateReportForId((Id id, DateTime day) arg)
{
LogInformation(); // shortcut
GetDataFromDB(); // shortcut
CreateReportFromRecordFromDB(); // shortcut
UpdateInformationInDBThatReportHasBeenGenerated(); // shortcut
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.