问题1。
使用Parallel.For和Parallel.ForEach更适合处理有序或无序的任务吗?
我要问的原因是我最近更新了一个串行循环,其中StringBuilder用于根据各种参数生成SQL语句。结果是,与使用标准foreach循环相比,SQL有点混乱(到了包含语法错误的程度),因此我的直觉是TPL不适合执行数据必须出现在特别的顺序。
问题2。
TPL是否自动使用多核架构,我必须在执行前配置任何内容?
我提出此问题的原因与我提出的有关TPL操作性能分析的问题有关。对这个问题的回答使我明白TPL并不总是比标准串行循环更有效,因为应用程序可能无法访问多个内核,因此创建额外线程和循环的开销会导致性能下降到标准的串行循环。
答案 0 :(得分:2)
我的直觉是,TPL不适合执行数据必须以特定顺序出现的任务。
正确。如果你期望事情有序,你可能会误解你在“并行化”一个循环时会发生什么。
TPL是否自动使用多核架构,我必须在执行前配置任何内容?
请参阅msdn杂志上的以下文章: http://msdn.microsoft.com/en-us/magazine/cc163340.aspx
使用该库,您可以方便地表达潜在的并行性 在现有的顺序代码中,暴露的并行任务将在其中 在所有可用的处理器上并发运行。
答案 1 :(得分:1)
如果必须对结果进行排序,那么为了使循环并行化,您需要能够以任何顺序进行实际工作,然后对结果进行排序。根据情况,这可能比首先连续工作更有效或更高效。如果以任何顺序进行并行化工作的好处超过了对结果进行排序的成本,那么它就是净增益。如果该任务不够复杂,您的硬件不允许大量并行化,或者如果它没有很好地并行化(即由于数据依赖性而需要大量等待),那么对结果进行排序可能需要更多比并行化循环所获得的时间(或者更糟糕的是,即使没有排序,并行化循环也需要更长时间,请参阅问题二),因此您不应该将其并行化。
请注意,如果实际工作单元需要按特定顺序运行,而不是仅按特定顺序运行结果,那么您将无法将其并行化,或者您将无法几乎同样有效地并行化。如果您没有正确地同步访问共享资源,那么您实际上会得到错误的结果(如您的情况所示)。为此,您需要记住,如果您无法获得正确的结果,性能优化就毫无意义。
您不需要担心TPL的硬件问题。您无需显式添加或限制任务。虽然有几种方式可以 ,但几乎任何时候你做这样的事情都会损害性能。当你做这样的事情时,你就是向TPL添加限制因此它无法做到它想做的事情。通常它比你更清楚。
你也可以在这里触及另一个点,那就是并行循环通常需要更长的时间(你只是没有给出导致这种行为的可能原因)。通常,需要完成的实际工作非常小,以至于创建线程,管理线程,处理上下文移动以及根据需要同步数据的工作可能比通过并行执行某些工作获得的工作更多。这就是为什么在决定并行化某些工作以确保实际从中受益时,实际进行大量测试非常重要的原因。
答案 2 :(得分:0)
在第1点,如果使用TPL,您不知道运行哪个任务的顺序。这就是并行与顺序之美。有办法控制事物的顺序,但你可能会失去并行的好处。
On 2:TPL开箱即用多核。但是使用多个线程确实总是有开销。调度程序上的负载增加,线程(上下文)切换不是免费的。为了保持数据同步以避免竞争条件,您可能需要一些锁定机制,这也会增加开销。
使用TPL制作快速并行算法变得更加容易,但仍然是某种艺术。
答案 3 :(得分:0)
对于无序列表,它不是更好或更糟 - 您在#1中的问题是您对StringBuilder
的共享依赖关系是并行查询失败的原因。 TPL在独立工作单元上运行良好。即使这样,也可以使用简单的技巧强制评估并行查询,并在并行操作全部完成时保持结果的原始顺序。
TPL和PLINQ在技术上是截然不同的; PLINQ使用TPL来实现它的目标。也就是说,PLINQ尝试检查您的体系结构并尽可能地构建集合的执行。 TPL只是围绕任务架构的包装器。由您决定创建任务(类似于1MB内存)的开销以及执行任务的上下文切换的开销是否大于简单地串行运行任务。
答案 4 :(得分:0)
显然,TPL不是构建像查询这样的有序集的好工具。
如果要对一组项目执行一系列任务,则可以使用BlockingCollection。任务可以并行执行,但保持该组的顺序。