我有一个for循环的实现,我使用TPL进行并行化。我正在使用配备4GB RAM和i3 Core处理器的戴尔笔记本电脑。我有多个GNU Emacs 25.1.1
Fedora release 24 (Twenty Four)
Gradle 2.14.1
使用parallel.foreach
调用。该程序是Enterprise Architect的一个插件,用于在EA中创建模型图和对象。
代码是这样的:
Parallel.invoke
其中每个父项创建都是Parallel.invoke(()=>parent1Creation(),()=>parent2Creation(),...);
:
Parallel.foreach
我有一个问题,当我的循环大小增加,即大约1500-2000次迭代时,Enterprise Architect停止工作。
这是一个问题,因为我的笔记本电脑配置或我使用并行循环或企业架构师的方式。
我该如何解决呢?
答案 0 :(得分:3)
我不建议这种策略。一次运行大量的Parallel.ForEach循环不一定有助于您的性能(请参阅后面的警告),特别是如果每个Parallel.ForEach循环处理大量迭代。在某些时候,使用额外的线程将不再有利于您的性能,只会增加开销。
这里需要注意的是,Parallel.ForEach在为特定的foreach循环选择最佳线程数时通常是好的(但并不完美)。没有明确保证特定foreach循环将使用多少线程(或者甚至将并行运行),因此可以想象多个Parallel.ForEach循环实际上会增强您的性能。检查它的最好方法是使用调试器来查看它在任何给定点实际使用的线程数。如果它不是您所期望的,您可以检查Parallel.ForEach循环中代码的实现(例如);此时您还可以采取其他步骤来尝试提高性能(例如,对于IO绑定和其他非CPU绑定操作的良好异步/等待实现,以便线程可以执行更多工作 - 请参阅下文)。 / p>
琐碎的例子:假设你有一个系统,你有4个线程和4个核心,4个线程是系统上运行的唯一东西。 (显然这永远不会发生)。从调度的角度来看,明智的做法是让每个核心分别处理一个线程。假设每个线程一直处于忙碌状态(即它永远不会等待),如何添加额外的线程可以提高性能?如果你开始运行,例如,6个线程,那么显然至少有一个核心现在必须运行至少2个线程,这增加了额外的开销,没有明显的好处。这里简化(并且可能是不真实的)假设是您的任务100%受CPU限制,并且线程实际上在不同的核心上运行。如果其中一个假设是不真实的,那么这是一个明确的增强机会。例如,如果线程花费大量时间等待IO绑定操作的结果,则CPU上的多个线程实际上可以提高性能。您还可以考虑使用async / await实现来提高性能。
关键是在某些时候添加额外的线程不会给你带来任何性能上的好处,只是增加了开销(例如,如果所涉及的任务主要是CPU绑定的,而不是主要是IO绑定的,例如)。没有办法解决这个问题。
非CPU绑定操作(IO绑定任务,例如对服务器的调用),其中主要持久性等待来自CPU /内存外部的结果的结果以不同方式并行化。实际上,async / await not 必然会创建新线程;它的主要行为之一是将控制权返回给问题调用者的方法,如果可能的话,“尝试”在同一个线程上做其他工作。
重复我最喜欢的比喻,假设你出去吃10人一组。当服务员来接订单时,服务员要求订购的第一个人还没准备好,但其他九个人都是。服务员要做的正确的事情是,而不是等待第一个人准备订购,让其他9个人先订购,然后如果他已经准备好,那么之后会有第一个人订单。他肯定不带来第二个服务员等待一个人做好准备;在这种情况下,第二个服务员可能实际上不会减少完成订单所花费的总时间。这基本上是async / await试图完成的;如果所有操作都在等待服务器的结果,例如,理想情况下,您可以在等待时执行其他操作。
另一方面,为了扩展类比,肯定不服务员实际上做饭的情况。在这种情况下,添加更多人(通过类比,线程)将真正加快速度。
为了进一步扩展这个类比,如果所有的厨房都是四个燃烧器的炉子,那么在他们遇到炉灶尺寸所施加的硬限制之前,你可以向厨房工作人员添加多少人的硬限制。一旦你达到这个限制,更多的厨房工作人员实际上会放慢速度,因为他们只会相互接触,因为实际上可以一次烹饪的东西数量有一个硬性限制。无论您的厨房工作人员有多大,您都不可能同时在炉子上烹饪超过4件物品。在这种情况下,您拥有的核心数量就像厨房大小;一旦达到某一点,添加更多厨房工作人员(线程)将降低您的表现(不会增强它)。
答案 1 :(得分:2)
如果你使用RDBMS支持的模型,你最好不要对模型做一些SQL来快速完成任务,而不是使用EA的API。
https://leanpub.com/InsideEA有很多关于结构的细节。
e.g。使用SQLServer,使用原始INSERT比使用EA对象快得多,更不用说JOIN来快速获取数据了。
我的脚本比使用API的性能接近100倍以上。
不确定是否可以像您想要的那样调用EA COM对象。如果是,模型更新仍然必须以某种顺序发生,以便正确分配Object_ID。这可以解释为什么你会以某种锁定限制运行。