【发布时间】:2023-03-07 08:00:01
【问题描述】:
我尝试使用System.Threading.Tasks 库将一个简单的顺序循环转换为并行计算循环。
代码编译,返回正确结果,但不节省任何计算成本,否则耗时较长。
编辑:对不起,伙计们,我可能过于简化了这个问题,并在这样做时犯了一些错误。 为了附加更多信息,我在 i7-4700QM 上运行代码,它在 Grasshopper 脚本中被引用。 这是实际的代码。我也切换到了非线程局部变量
public static class LineNet
{
public static List<Ray> SolveCpu(List<Speaker> sources, List<Receiver> targets, List<Panel> surfaces)
{
ConcurrentBag<Ray> rays = new ConcurrentBag<Ray>();
for (int i = 0; i < sources.Count; i++)
{
Parallel.For(
0,
targets.Count,
j =>
{
Line path = new Line(sources[i].Position, targets[j].Position);
Ray ray = new Ray(path, i, j);
if (Utils.CheckObstacles(ray,surfaces))
{
rays.Add(ray);
}
}
);
}
}
}
Grasshopper 实现只是收集sourcestargets 和surfaces,调用方法Solve 并返回rays。
我知道将工作负载分派到线程是昂贵的,但它是如此昂贵吗?
还是ConcurrentBag 只是阻止并行计算?
另外,我的类是不可变的 (?),但如果我使用常见的 List,内核会中止操作并引发异常,有人能说出原因吗?
【问题讨论】:
-
并行循环通常只会让你的方法运行得更快,如果让你的方法变慢的是处理器(即 - 在四核计算机中,你的 CPU 使用率在整个方法运行期间保持在 25%运行,因为处理器一直在努力工作。)如果这是真的,那么将它分散到多个线程上会有所帮助。如果您的方法在硬盘驱动器或网络资源或其他东西上等待,它可能没有帮助。如果不了解有关如何生成
Lines或程序正在做什么的更多详细信息,很难说为什么这很慢... -
我们在您的测试中讨论了多少行?会有一些初始开销,因此好处可能不会立即明显。另一件事是
result.Add(line);将阻止任何线程也想调用与您使用ConcurrentBag相同的行 -
This answer 可能提供信息。
-
@ElementalPete 我更新了问题以便更好地解释问题。 @TyCobb 数十万行。
sources有 200 个点,targets有 200 个点,它在并行模式下分析 3.2 秒,在顺序计算下分析 2.9 秒。 @DourHighArch 一个非常足智多谋的答案,有助于调查问题
标签: c# multithreading parallel-processing thread-safety thread-local