提问人:Tenza 提问时间:3/8/2023 最后编辑:Theodor ZouliasTenza 更新时间:3/8/2023 访问量:261
在 C 语言中并行运行特定任务的正确方法#
Proper way to run a specific task in parallel in C#
问:
我有一个运行并执行某些方法的 Windows C# BackgroundService 进程。我想利用系统上的多线程运行此方法以尽可能多地进行处理。该方法包含一个数据库事务,并在其中根据该事务执行一些文件 I/O。我不需要任务的结果,只需要尽快运行它们。DoWork
目前,我让它运行如下例所示。这有效,我确实看到了性能的提高,但这似乎不是正确的方法。我也看到了使用的能力,但我看到了与 .我想做的是不断利用可用的线程来执行。我这样做是否正确,或者有更好的方法可以做到这一点?Task.Run
WaitAll
Parallel.For
DoWork
编辑:现在,除了对 .DoWork
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service running.");
Parallel.For(0, 8, task => {
await DoWork(stoppingToken);
});
await Task.Delay(Timeout.Infinite, stoppingToken);
}
private async Task DoWork(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is working.");
using (var transactionScope = new TransactionScope())
{
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// get initial query which gets the row with data needed
// to perform the file I/O and build request
var query = "SELECT TOP(1) FROM MyTable" +
" WITH (readpast, rowlock, updlock)";
var row = connection.Query<MyType>(query);
// based on query, perform file i/o
var file = File.ReadAllText(row.FileName);
var data = JsonSerializer.Deserialize<MyData>(file);
var item = new MyObject() { Id = data.Id, Name = data.Name };
// call a WCF web service using item object, the web service
// has no asynchronous methods
service.SendRequest(item);
// update the transaction and then close
var updateQuery = "UPDATE MyTable SET Status = @Status WHERE Id = @Id";
connection.Execute<MyType>(updateQuery);
transactionScope.Complete();
}
}
catch(Exception ex)
{
// Log error
transactionScope.Dispose();
}
}
}
答:
1赞
Theodor Zoulias
3/8/2023
#1
由于面向 .NET 7,因此可以使用 .NET 6 API Parallel.ForEachAsync
:
ParallelOptions options = new()
{
MaxDegreeOfParallelism = 2,
CancellationToken = stoppingToken,
};
await Parallel.ForEachAsync(Enumerable.Range(0, 8), options, async (_, ct) =>
{
await DoWork(ct);
});
您可以尝试使用 MaxDegreeOfParallelism
选项,直到找到手头任务的最佳值。从一个小值开始,逐渐增加它,直到性能停止提高。
评论
0赞
Tenza
3/9/2023
在这种情况下,除了使用并行处理之外,还有什么方法可以提高性能吗?由于这一切都是同步的,而且我确实有一个网络请求,因此并行处理似乎只有这么多好处。Parallel.For
0赞
Theodor Zoulias
3/9/2023
@Tenza,有可能优化与数据库相关的工作。通过减少查询(批处理、批量操作)执行更多工作,或者改进查询执行计划(添加索引等)。但这超出了这个问题的范围。
评论
Parallel.For
不是任务感知,JIC。