parallel-processing - 任务怎么写? (平行码)

标签 parallel-processing tbb

我对英特尔线程构建 block 印象深刻。我喜欢我应该如何编写任务而不是线程代码,并且我喜欢它在我有限的理解下如何工作(任务在一个池中,4核上不会有100个线程,一个任务不能保证运行,因为它不在它自己的线程并且可能远离池。但它可能与另一个相关任务一起运行,因此您不能做典型的线程不安全代码之类的坏事)。

我想了解更多关于写作任务的信息。我喜欢这里的“基于任务的多线程 - 如何为 100 个内核编程”视频 http://www.gdcvault.com/sponsor.php?sponsor_id=1 (目前倒数第二个链接。警告它不是“好”)。我最喜欢的部分是“最好并行解决迷宫”,大约在 48 分钟左右(您可以单击左侧的链接。如果有的话,这部分确实是您需要观看的全部内容)。

但是我喜欢看更多的代码示例和一些关于如何编写任务的 API。谁有好的资源?我不知道一个类或一段代码在将其推送到池后会是什么样子,或者当您需要复制所有内容以及将所有内容推送到池中时,代码看起来会如何。

最佳答案

Java 有一个类似于 Thread Building Blocks 的并行任务框架——它被称为 Fork-Join 框架。它是 available用于当前的 Java SE 6 并包含在即将推出的 Java SE 7 中。

除了 javadoc 类文档之外,还有一些资源可用于开始使用该框架。来自 jsr166 page , 提到
“还有一个 wiki,其中包含这些类(class)的附加文档、注释、建议、示例等。”

fork-join examples ,例如矩阵乘法是一个很好的起点。

我使用 fork-join 框架解决了一些 Intel's 2009 threading challenges .该框架是轻量级且开销低的——我的框架是骑士巡回赛问题的唯一 Java 条目,它在比赛中的表现优于其他条目。 Java 源代码和文章可从挑战站点下载。

编辑:

I have no idea how a class or pieces of code may look after pushing it onto a pool [...]



您可以通过继承 ForKJoinTask 之一来完成自己的任务。子类,例如 RecursiveTask .这是并行计算斐波那契数列的方法。 (取自 RecursiveTask javadocs - 评论是我的。)
 // declare a new task, that itself spawns subtasks. 
 // The task returns an Integer result.
 class Fibonacci extends RecursiveTask<Integer> {
   final int n;      // the n'th number in the fibonacci sequence to compute
   Fibonnaci(int n) { this.n = n; } // constructor
   Integer compute() {   // this method is the main work of the task
     if (n <= 1)         // 1 or 0, base case to end recursion
        return n;
     Fibonacci f1 = new Fibonacci(n - 1);  // create a new task to compute n-1
     f1.fork();                            // schedule to run asynchronously
     Fibonacci f2 = new Fibonacci(n - 2);  // create a new task to compute n-2
     return f2.invoke() + f1.join();       // wait for both tasks to compute.
       // f2 is run as part of this task, f1 runs asynchronously. 
       // (you could create two separate tasks and wait for them both, but running
       // f2 as part of this task is a little more efficient.
   }
 }

然后你运行这个任务并得到结果
// default parallelism is number of cores
ForkJoinPool pool = new ForkJoinPool(); 
Fibonacci f = new Fibonacci(100);
int result = pool.invoke(f);

这是一个简单的例子。在实践中,性能不会那么好,因为与任务框架的开销相比,任务执行的工作是微不足道的。根据经验,一项任务应该执行一些重要的计算——足以使框架开销变得微不足道,但又不会导致在运行一项大型任务的问题结束时使用一个核心。将大型任务拆分为较小的任务可确保一个核心不会在其他核心空闲时做大量工作 - 使用较小的任务会使更多核心保持忙碌,但不会小到该任务没有实际工作。

[...] or how weird code may look when you need to make a copy of everything and how much of everything is pushed onto a pool.



只有任务本身被插入池中。理想情况下,您不想复制任何内容:为了避免干扰和锁定的需要,这会减慢您的程序,您的任务理想情况下应该使用独立数据。只读数据可以在所有任务之间共享,不需要复制。如果线程需要合作构建一些大型数据结构,最好将它们单独构建,然后在最后将它们组合起来。组合可以作为一个单独的任务完成,或者每个任务都可以将它的一部分添加到整体解决方案中。这通常确实需要某种形式的锁定,但如果任务的工作量远大于更新解决方案的工作量,这不是一个相当大的性能问题。 My Knight's Tour 解决方案采用这种方法来更新板上的通用旅行存储库。

与常规单线程编程相比,处理任务和并发性是一个相当大的范式转变。通常有几种设计可以解决给定的问题,但只有其中一些适合线程解决方案。可能需要几次尝试才能了解如何以多线程方式重铸熟悉的问题。最好的学习方法是查看示例,然后自己尝试。始终分析和测量不同线程数的影响。您可以在池构造函数中显式设置要在池中使用的线程(核心)数。当任务被线性分解时,随着线程数量的增加,您可以预期接近线性的加速。

关于parallel-processing - 任务怎么写? (平行码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2814838/

相关文章:

c++ - deque.tcc 错误 : expected primary-expression before '>' token

c++ - 您的计算机缺少 tbb.dll

python - 调试并行 Python 程序 (mpi4py)

java - 如何从Java中的并行数组中删除重复项?

multithreading - 使用 GPU 进行并行 for 循环的最简单方法

c++ - 将 openmp 更改为 tbb

c++ - 使用 lambda 的线程构建 block (TBB) 排队任务

Java设置多线程处理

python - 使用 python 3.6 将多个文件并行加载到内存中的最佳方法是什么?

c++ - 用于服务网络连接的英特尔 TBB 任务 - 好的模型?