而不是手动添加PLinq扩展语句AsParallel(),编译器无法自动为我们解决这个问题吗?如果代码支持,是否有任何特别不希望并行化的示例?
答案 0 :(得分:2)
我在自动并行化领域做研究。这是一个非常棘手的话题,是许多博士的主题。论文。静态代码分析和自动并行化已经为Fortran等语言取得了巨大成功,但编译器分析区域间依赖关系的能力有限。大多数人不愿意牺牲代码正确性的保证来换取潜在的并行性能增益,因此编译器在插入并行标记的位置必须非常保守。
底线:是的,编译器可以并行化代码。但是人类通常可以更好地并行化它,让编译器弄清楚放置标记的位置可能非常非常非常棘手。有关该主题的数十篇研究论文,例如Mitosis并行化编译器的背景工作或D-MPI工作。
答案 1 :(得分:2)
自动并行化比最初出现时更棘手。这是“如果代码支持它”的一部分,它可以帮到你。考虑像
这样的东西counter = 0
f(i)
{
counter = counter + 1
return i + counter
}
result = map(f, {1,2,3,4})
如果编译器决定在此处并行化地图,则可以在程序的每次运行中获得不同的结果。很明显,f实际上并不支持以这种方式使用,因为它有一个全局变量。但是,如果f在不同的程序集中,则编译器无法知道并行化它是不安全的。它可以反思程序集f在运行时并且然后决定,但随后它变成了一个问题:“内省是否足够快,并且动态并行化的速度足够快以至于不能否定这样做的好处?”有时可能无法内省,f
可能是P / Invoked函数,实际上可能非常适合并行化,但由于运行时/编译器无法知道它必须假设它可以'是的。这只是冰山一角。
简而言之,这是可能的,但很难,所以实施魔法和魔法的好处之间的权衡可能在错误的方向上偏得太远。
答案 2 :(得分:2)
好消息是编译器研究人员说我们真的接近自动并行化编译器。坏消息是,他们已经说了五十年了。
C#等不纯语言的问题通常是没有足够的并行性。在一种不纯洁的语言中,对于一个人来说很难并且几乎不可能找出两段代码是否以及如何相互作用或与环境相互作用。
在纯粹的,引用透明的语言中,你有相反的问题:所有都是可并行的,但它通常没有意义,因为调度一个线程比简单地执行该死的东西。
例如,在纯粹的,引用透明的功能语言中,如果我有这样的东西:
if a <= b + c
foo
else
bar
end
我可以启动五个线程并并行计算a
,b
,c
,foo
和bar
,然后计算{{1然后是+
,最后,我计算<=
,这只是意味着丢弃已经计算过的if
或foo
的结果。 (注意这取决于功能如何:在一种不纯的语言中,你不能简单地计算bar
的两个分支,然后扔掉一个分支。如果两个分别打印什么怎么办?你怎么“打印”那个?)
但如果if
,a
,b
,c
和foo
非常便宜,那么这五个主题的开销将远远大于计算本身。