使用GPars解决常见并发问题 - 编程入门网
池
async和 callAsync方法不阻止线程并立即返回一个 Future对象来表示异步计算的未来结果。接收者可以要求 Future阻止线程,直至一个结果就绪,检测查看它是否完成并取消计算指令,或检查是否有其他进程取消了它。与 Executor接口一样,Future类是底层 java.util.concurrent包的一部分。 使用GPars解决常见并发问题(4)时间:2012-03-17 IBM Alex MillerCPU 的并行性 在后台处理示例中,您了解了让一个程序并行等待多个 I/O 密集型任务(而非串行处理它们)的好处。使用一批作业员来并行执行多个任务对 CPU 密集型任务也大有裨益。 您的应用程序的两个重要方面影响着它可以接受的并行度,因此您具有的编程选项包括: 任务粒度,即任务在时间或数据上的范围 任务依赖性,即通常存在于任务之间的依赖关系的数量 两个方面存在于一个状态集上,且在制定一个解决方案之前考虑该状态集上的问题所在是很有用的。例如,一个程序的任务粒度可由大型事务级工作定义,它也可以由大型数据集一小部分(整幅图像的几个像素)中的多个简短的计算指令组成。由于任意工作量的一个线程或进程的上下文切换涉及到的开销较大,小粒度级的系统往往效率低下且遭遇低性能问题。基于任务粒度的批处理是为您的系统找到最佳性能点的一种方法。 依赖性较少的任务通常被描述为 “高度平行”,即太容易将它们分成多个并行任务了。典型的例子包括图形处理、强力搜索、分形和粒子模拟。任何处理或转换大批命令或文件的业务处理程序也可归入这一类。 Executor 队列争用 我们已经探究了如何使用 GPars 将任务推入 Executor池的机理。不过,最好要记住,Executor是在 2005 年某个时候添加到 Java 2 Platform、Standard Edition (J2SE) 的。它们是为相对少数的核心(2 到 8 个)而调优的,这些核心运行粗粒度的、可能会阻止具有较少任务相关性的事务型任务。Executor是在单个传入的工作队列由多个工作线程共享的情况下实现的。 对于该模型的一个关键问题是增加工作线程数会加剧对工作队列的争用(如图 3 所示)。这种争用最终会随线程和核心的增多而成为一个可伸缩性瓶颈。 图 3. Executor 队列争用 Executor队列的一个替代项是 fork/join 框架,该框架目前存有 JSR 166y 维护更新,且会在 JDK 7 中正式引入 Java 平台。Fork/join 是为运行细粒度计算任务的大量并发任务而调优的。 GPars 中的 Fork/join Fork/join 支持定义任务间的依赖关系和生成新任务;这些属性使其成为分而治之风格算法的理想之选,该算法将一个任务分为若干子任务,然后重新将子计算指令联合起来。通过让一个线程拥有一个工作队列,Fork/join 解决了队列争用的问题。所有情况下使用的队列其实是一种 双队列(deque)(两端都能输入数据的数据行列,发音为 “deck”),它允许线程从另一个队列的后端窃取工作,从而平衡进入线程池的工作。 以查找列表中最大值的任务为例。最明显的战略是简单地遍历所有数字,在遍历过程中密切注意最大值。但是,这本质上是一种串行战略,且不利用那些昂贵的核心。 而如果我将最大值函数作为一个分而治之的并行算法来实现,想想会发生什么。分而治之算法是一种递归算法;每一步都具有如清单 5 所示的结构: 清单 5. 分而治之算 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |