【发布时间】:2021-11-25 07:14:58
【问题描述】:
给定:
- 数百个 .NET 项目
- 所有项目中的数千个 C# 文件
- 字符串文字
我想在所有项目的所有文件中输出给定文字的所有匹配项。我想使用这个示例来了解如何优化简单 TPL DataFlow 管道的性能。
完整代码提交在github - https://github.com/MarkKharitonov/LearningTPLDataFlow/blob/master/FindStringCmd.cs
管道本身是:
private void Run(string workspaceRoot, string literal, int maxDOP1 = 1, int maxDOP2 = 1)
{
var projects = (workspaceRoot + "build\\projects.yml").YieldAllProjects();
var produceCSFiles = new TransformManyBlock<ProjectEx, CSFile>(YieldCSFiles, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = maxDOP1 });
var produceMatchingLines = new TransformManyBlock<CSFile, MatchingLine>(csFile => csFile.YieldMatchingLines(literal), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = maxDOP2 });
var getMatchingLines = new ActionBlock<MatchingLine>(o => Console.WriteLine(o.ToString(workspaceRoot)));
var linkOptions = new DataflowLinkOptions { PropagateCompletion = true };
produceCSFiles.LinkTo(produceMatchingLines, linkOptions);
produceMatchingLines.LinkTo(getMatchingLines, linkOptions);
Console.WriteLine($"Locating all the instances of {literal} in the C# code ... ");
var sw = Stopwatch.StartNew();
projects.ForEach(p => produceCSFiles.Post(p));
produceCSFiles.Complete();
getMatchingLines.Completion.Wait();
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
这里有一些注意事项:
- 获取
ProjectEx对象非常便宜。 - 第一次访问
ProjectEx.MSBuildProject属性非常昂贵。这是 Microsoft Build API 评估相应 csproj 文件的地方。 - 经过评估获得 CS 文件列表非常便宜,但处理它们的成本相当高,因为它们太多了。
我不确定如何在这里以图形方式描述管道,但是:
-
produceCSFiles被提供廉价的ProjectEx对象并输出大量CSFile对象,由于项目评估,这很昂贵。 -
produceMatchingLines被提供CSFile对象并输出匹配的行,由于CSFile对象的数量和要处理的行数量,这很昂贵。
我的问题 - 我的实现是最优的吗?我有疑问,因为增加maxDOP1 和maxDOP2 并不会产生太大的改进:
C:\work\TPLDataFlow [master ≡ +0 ~2 -0 !]> 1..4 |% { $MaxDOP1 = $_ ; 1..4 } |% { $MaxDOP2 = $_ ; $res = .\bin\Debug\net5.0\TPLDataFlow.exe find-string -d C:\dayforce\tip -l GetClientLegalPromptFlag --maxDOP1 $MaxDOP1 --maxDOP2 $MaxDOP2 -q ; "$MaxDOP1 x $MaxDOP2 --> $res" }
1 x 1 --> Elapsed: 00:00:21.1683002
1 x 2 --> Elapsed: 00:00:19.8194133
1 x 3 --> Elapsed: 00:00:20.2626202
1 x 4 --> Elapsed: 00:00:20.4339065
2 x 1 --> Elapsed: 00:00:17.6475658
2 x 2 --> Elapsed: 00:00:15.4889941
2 x 3 --> Elapsed: 00:00:14.9014116
2 x 4 --> Elapsed: 00:00:14.9254166
3 x 1 --> Elapsed: 00:00:17.6474953
3 x 2 --> Elapsed: 00:00:14.4933295
3 x 3 --> Elapsed: 00:00:14.2419329
3 x 4 --> Elapsed: 00:00:14.1185203
4 x 1 --> Elapsed: 00:00:19.0717189
4 x 2 --> Elapsed: 00:00:15.9069517
4 x 3 --> Elapsed: 00:00:16.3267676
4 x 4 --> Elapsed: 00:00:17.0876474
C:\work\TPLDataFlow [master ≡ +0 ~2 -0 !]>
我看到的是:
- 最大改进是
maxDOP1 == 3和maxDOP2 == 4- 14.12 秒 vs 21.17 秒 - 最大投资回报率是
maxDOP1 == 2和maxDOP2 == 3- 15 秒 vs 21.17 秒
总而言之,仅比单线程版本提高了 30%。这有点令人失望,因为所有文件都在 SSD 上,而且我有 12 个逻辑处理器。当然,代码要复杂得多。
我错过了什么吗?也许我没有以最佳方式做到这一点?
【问题讨论】:
标签: c# task-parallel-library tpl-dataflow