简体   繁体   English

Parallel.ForEach挂起一个大循环

[英]Parallel.ForEach hangs for a large loop

I have an implementation of for loops that I am parallelizing using TPL. 我有一个使用TPL并行化的for循环实现。 I am using a Dell laptop with 4GB RAM and i3 Core processor. 我正在使用配备4GB RAM和i3 Core处理器的Dell笔记本电脑。 I have multiple parallel.foreach which are invoked using Parallel.invoke . 我有多个parallel.foreach其使用调用Parallel.invoke This program is an addin to Enterprise Architect for creating the model diagram and objects in EA. 该程序是Enterprise Architect的插件,用于在EA中创建模型图和对象。

Code is something like this: 代码是这样的:

Parallel.invoke(()=>parent1Creation(),()=>parent2Creation(),...);

where each parent creation is a Parallel.foreach : 其中每个父级创建都是Parallel.foreach

Parallel.foreach(parents, (parent) => {
    //create parent 
    //create children
    for(child in parent.children) {
        childecreation();
    }

    for(child2 in parent.children) {
        childecreation();
    }
    //can be any type and number of children
} 

I have an issue that when my loop size increases ie around 1500-2000 iterations, Enterprise Architect stops working. 我有一个问题,当我的循环大小增加(即大约1500-2000次迭代)时,Enterprise Architect停止工作。

Is this an issue because of my laptop configuration or the way I am using parallel loops or with Enterprise architect. 这是因为我的笔记本电脑配置,还是我使用并行循环或企业架构师的方式而引起的问题?

How can I resolve it. 我该如何解决。

I don't suggest this strategy. 我不建议这种策略。 Running lots of Parallel.ForEach loops at once won't necessarily help your performance (see the caveat later in the post), especially if each of the Parallel.ForEach loops is handling a large number of iterations. 一次运行许多Parallel.ForEach循环并不一定会提高性能(请参阅后面的注意事项),尤其是在每个Parallel.ForEach循环正在处理大量迭代的情况下。 At some point, using additional threads won't benefit your performance anymore and will just add overhead. 在某些时候,使用额外的线程将不再对您的性能有所帮助,只会增加开销。

The caveat here is that Parallel.ForEach is generally good (but not perfect) at selecting the optimal number of threads for a particular foreach loop. 需要注意的是,Parallel.ForEach通常可以为特定的foreach循环选择最佳线程数(但并不完美)。 There's no explicit guarantee as to exactly how many threads a particular foreach loop will use (or even that it will run in parallel), so it's conceivable that multiple Parallel.ForEach loops will, in fact, enhance your performance. 没有明确保证特定的foreach循环将使用多少线程(甚至并行运行),因此可以想象多个Parallel.ForEach循环实际上可以提高性能。 The best way to check that is to use the debugger to see how many threads it's actually using at any given point. 最好的检查方法是使用调试器查看在给定点实际使用了多少个线程。 If it's not what you'd expect, you might check the implementation of the code in the Parallel.ForEach loop (for example); 如果不是您所期望的,则可以检查Parallel.ForEach循环中代码的实现(例如); there are other steps you could take at this point to try to improve the performance (eg a good async/await implementation for IO-bound and other non-CPU-bound operations so that the thread can do more work - see below). 此时,您还可以采取其他步骤来尝试提高性能(例如,针对IO绑定和其他非CPU绑定操作的良好async / await实现,以便线程可以执行更多工作-参见下文)。

Trivial example: suppose you have a system where you have 4 threads and 4 cores and the 4 threads are the only things that are running on the system. 一个简单的例子:假设您有一个系统,其中有4个线程和4个内核,而这4个线程是系统上运行的唯一对象。 (Obviously this'll never happen). (显然,这永远不会发生)。 The sensible thing from a scheduling point of view would be to have each core handle one thread each. 从调度的角度来看,明智的做法是让每个内核分别处理一个线程。 Assuming that each of the threads is busy all the time (ie it's never sitting around waiting) how could adding additional threads improve your performance? 假设每个线程一直都在忙(即从不等待),那么如何添加更多线程来提高性能呢? If you start running, for example, 6 threads then obviously at least one core will now have to run at least 2 threads, which adds extra overhead with no clear benefit. 例如,如果您开始运行6个线程,那么显然至少一个内核现在必须至少运行2个线程,这增加了额外的开销,并且没有明显的好处。 The simplifying (and possibly untrue) assumptions here are that your tasks are 100% CPU-bound and that the threads are, in fact, running on separate cores. 这里的简化(可能是错误的)假设是您的任务受100%CPU限制,并且线程实际上在单独的内核上运行。 If one of these assumptions are untrue, that's a clear opportunity for enhancement. 如果这些假设之一是不正确的,那显然是一个增强的机会。 For example, if a thread spends a significant amount of time waiting for results from IO-bound operations, multiple threads on the CPU could, in fact, improve performance. 例如,如果一个线程花费大量时间等待IO绑定操作的结果,则CPU上的多个线程实际上可以提高性能。 You could also consider an async/await implementation to improve performance. 您也可以考虑使用异步/等待实现来提高性能。

The point being that at some point adding additional threads won't give you any performance benefit, just added overhead (especially if the tasks involved are mostly CPU-bound rather than mostly IO-bound, for example). 关键是,在某个时候添加额外的线程不会给您带来任何性能上的好处,只是增加了开销(例如,如果所涉及的任务主要是CPU约束的,而不是大多数IO约束的,则尤其如此)。 There's no way around that fact. 无法解决这个事实。

Non-CPU-bound operations (IO-bound tasks like calls to servers, for example) where the main holdup is waiting for a result from something external to the CPU/memory are parallelized differently. 非CPU绑定操作(例如,对服务器的调用等IO绑定任务)在主保持等待来自CPU /内存外部的结果的情况下,以不同的方式并行化。 In fact, async/await does not necessarily create new threads; 事实上,异步/等待并不一定创造新的线程; one of its major behaviors is to return control to the method in question's caller and "try" to do other work on the same thread if possible. 它的主要行为之一是将控制权返回给有问题的调用者,并在可能的情况下“尝试”在同一线程上执行其他工作。

To repeat my favorite analogy, suppose that you go out to eat as part of a group of 10 people. 重复我最喜欢的类比,假设您是10人一组的一部分出去吃饭。 When the waiter comes by to take orders, the first guy the waiters asks to order isn't ready but the other nine people are. 当服务员来点菜时,服务员要点菜的第一个家伙还没准备好,而其他九个人已经准备好了。 The correct thing for the waiter to do is, rather than wait for the first guy to be ready to order, to have the other 9 people order first and then have the first guy order afterwards if he's ready by then. 服务员要做的正确的事情是,要等其他9个人先点菜,然后再等第一个人点菜,而不是等第一个人要点菜时才准备。 He definitely does not bring in a second waiter to wait for the one guy to be ready; 他绝对不会在第二个服务员把等待一个人做好准备; in this case, the second waiter probably wouldn't actually reduce the total amount of time taken to complete the order. 在这种情况下,第二个服务员可能实际上不会减少完成订单所需的总时间。 This is basically what async/await tries to accomplish; 这基本上是异步/等待尝试完成的任务; if all an operation is doing is waiting for a result from a server, for example, ideally you'd be able to do other things while it's waiting. 例如,如果所有操作正在等待服务器的结果,则理想情况下,您可以在服务器等待时执行其他操作。

On the other hand, to extend the analogy, it's definitely not the case that the waiter actually makes the meal itself. 另一方面,要扩大类比,服务员实际上不是自己做饭,绝对不是这种情况。 In that case, adding more people (by analogy, threads) would genuinely speed things up. 在那种情况下,增加更多的人(以类推,线程)将真正加快速度。

To extend the analogy even further, if all the kitchen has is a four-burner stove, then there's a hard limit to how many people you can add to the kitchen staff before they run into the hard limit imposed by the stove size. 进一步推论,如果所有厨房都只有一个四燃烧炉,那么在可以增加多少人之前,就没有一个硬性限制,因为他们遇到了火炉尺寸所带来的硬性限制。 Once you hit that limit, more kitchen staff will actually slow things down because they'll just be getting in each other's way because there's a hard limit to the number of things that can actually be cooking at once. 一旦达到这个极限,实际上更多的厨房工作人员就会放慢脚步,因为他们会互相干扰,因为实际上一次烹饪的食物数量有一个严格的限制。 No matter how big your kitchen staff is, you can't possibly have more than 4 items cooking on the stove at once. 不管您的厨房员工多大,都不可能一次在炉子上烹饪超过4种食物。 In this case, the number of cores you have is like the kitchen size; 在这种情况下,您拥有的核心数就如同厨房的大小; once you reach a certain point, adding more kitchen staff (threads) will detract from your performance (not enhance it). 一旦达到某个点,增加更多的厨房工作人员(线程)将损害您的绩效(而不是提高绩效)。

If you use a RDBMS backed model, you are better off doing some SQL against the model to get things done fast instead of using EA's API. 如果使用RDBMS支持的模型,最好对模型执行一些SQL,以快速完成工作,而不要使用EA的API。

https://leanpub.com/InsideEA has a lot of details on the structure. https://leanpub.com/InsideEA在结构上有很多细节。

eg With SQLServer, you are going to be so much faster with raw INSERTs than walking through EA objects, not to mention JOINs to get data out fast. 例如,使用SQLServer,使用原始INSERT的速度将比遍历EA对象的速度快得多,更不用说用JOIN来快速获取数据了。

I have scripts having close to 100x + more performance w/ SQL than using the API. 与使用API​​相比,我的脚本具有比SQL接近100倍的性能,并且具有更高的SQL性能。

Not sure EA COM object is able to be invoked like you want. 不确定EA COM对象是否能够按您希望的方式被调用。 And if it is, model updates will still have to occur in some kind of sequence for Object_IDs to be assigned properly. 如果是这样,则仍必须以某种顺序进行模型更新,才能正确分配Object_ID。 This may explain why you would run in some kind of locking limit. 这可以解释为什么您将以某种锁定限制运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM