分布式计算中多队列线程池的设计与实现
分布式线程池模型的设计与实现

α
分布式线程池模型的设计与实现
帖 军
(中南民族大学 计算机科学学院, 武汉 430074)
摘 要 针对传统线程池的弊端, 设计了一个分布式线 程池系统模型, 该系统可在池内部 实施功能分布、 动态自我 调整和任务透明传递 执行 . 给出了 该线程池内部的主 要对象结构, 并对 池内对象在 池资源的多 元性及统一 接口实 现、 负载平衡与任务透明转移以及池结构的动态监控管理与优化等几个方面的功能协作给出了详细的设计 . 关键词 分布式系统; 线程池; 并发; 负载平衡 中图分类号 TP 311. 1 文献标识码 A 文章编号 1672 2 4321(2007) 02 2 00792 04
线程池技术的应用需求来自于目前广泛使用的 分布式系统 . 在诸如 W eb 服务器、 数据库服务器、 文 件服务器或邮件服务器之类的许多服务器应用程序 中, 系统往往需要接受突发性的、 数量巨大的瞬时客 户请求 . 线程池提供了解决系统性能和突发性、 大 用户量瞬时请求之间矛盾的方法 , 通过对多个任务 重用已经存在的线程对象, 降低了线程对象创建和 销毁的开销 . 当用户请求来到时 , 线程对象已经存 在, 系统无需创建线程即可直接进入应用; 任务完成 后, 线程对象并不撤销, 以备下一个用户请求重复使 用, 这样就降低了请求的响应时间 , 从而整体上提高 了系统服务的质量 . 目前普通线程池模型的工作环境都局限于单机 高性能服务器 , 任务仅限于客户端和中间件服务器 之间的分布和协作; 对于中间件服务器内部各资源 及线程之间的分布、 调度和协作机制则很少涉及. 这
α
收稿日期 20 06 2 0 9203 作者简介 帖 军 (1 97 62) , 男, 讲师, 研究方向: 分布式系统, E 2 m a il:m u sa @ scu ec. edu. cn
分布式系统中的任务队列与任务调度(二)

分布式系统中的任务队列与任务调度随着互联网的快速发展,分布式系统在各个行业中被广泛应用。
为了实现高效的任务处理和资源利用,任务队列与任务调度成为分布式系统中不可或缺的组成部分。
本文将从任务队列和任务调度的概念入手,探讨它们在分布式系统中的作用和应用。
一、任务队列任务队列是一种存储和管理任务的数据结构,用于协调分布式系统中的任务处理。
它将任务按照时间顺序排列,保证任务的顺序性。
每个任务都包含了需要执行的操作和相关的参数。
任务队列可以分为同步队列和异步队列两种形式。
同步队列是一种简单的队列模式,它依次处理每个任务。
当一个任务执行完毕后,才会执行下一个任务。
同步队列在一些对任务执行顺序有严格要求的场景中很常见,比如电商平台的订单处理。
在该平台中,每个订单必须按照下单的先后顺序进行处理,否则可能会引发支付、库存等问题。
异步队列则是一种非阻塞的队列模式,它可以同时处理多个任务。
每个任务被放入队列后,无需等待前一个任务的完成,就可以继续处理下一个任务。
异步队列适用于任务处理时间较长,可以并发执行的情况,比如视频转码、大数据分析等。
二、任务调度任务调度是一种动态分配任务资源和管理任务执行的机制。
它根据任务的优先级、资源情况和系统负载等因素,合理地分配任务给不同的节点进行处理。
任务调度能够充分利用系统资源,提高处理效率和性能。
在分布式系统中,任务调度通常分为两个层次:中心调度和节点调度。
中心调度负责全局任务调度,根据各个节点的负载情况和任务优先级,将任务分配给不同的节点。
节点调度则负责局部任务调度,根据节点自身的资源情况和任务执行情况,合理地分配和管理任务的执行。
任务调度的算法有多种,比如最短作业优先调度、先来先服务调度、最早截止时间优先调度等。
这些算法以任务的属性和系统的状态为基础,综合考虑各个因素,确定合适的任务执行顺序和调度策略。
合理的任务调度能够提高系统的负载均衡和效率。
三、任务队列与任务调度的应用任务队列与任务调度在分布式系统中有广泛的应用。
分布式计算平台的设计与实现

分布式计算平台的设计与实现随着互联网和计算机技术的迅猛发展,数据量的急速增加和计算速度的不断提高,分布式计算平台作为一种新型的计算方式,逐渐引起人们的关注和应用。
本文将探讨分布式计算平台的设计与实现。
一、什么是分布式计算平台分布式计算平台是指利用多台计算机资源进行分布式计算的一种计算模式。
它集合了多台计算机的计算能力和存储资源,通过网络将它们连接起来,形成一个庞大的计算机群。
在分布式计算平台中,各个计算机节点通过共享任务和结果,共同完成一项计算任务。
分布式计算平台的主要优势在于分布式计算的计算速度更快、计算能力更强、计算精度更高,并且具有较好的可扩展性和可靠性,同时减少计算能耗、节省成本,广泛应用于高性能计算、大规模数据分析、人工智能等领域。
二、分布式计算平台的设计原则分布式计算平台的设计需要考虑以下原则:(1)可扩展性:分布式计算平台为了适应不同规模的计算需求,需要具有较好的可扩展性,能够支持更多计算节点的加入和退出,这样可以在不同的项目开发和应用场景下满足不同的计算需求。
(2)可靠性:分布式计算平台需要具有良好的可靠性,防止单点故障出现,保证每个计算节点的可靠性和稳定性,以保证整个系统的稳定运行。
(3)任务分配:分布式计算平台需要能够把任务分配到各个计算节点上,根据不同计算节点的运行能力进行任务分配,以实现系统性能的优化。
(4)数据传输:分布式计算平台需要具有高效的数据传输能力,减少不必要的数据传输和存储,从而提高系统的传输速度和计算效率。
(5)安全性:分布式计算平台需要保证数据的安全性,尤其是在涉及到敏感数据的应用场景下,需要加强数据的加密和权限控制。
三、分布式计算平台的实现分布式计算平台的实现可以采用多种软件技术和编程语言,比如Hadoop、Spark、MapReduce、MPI等。
下面主要介绍基于Hadoop实现的分布式计算平台。
Hadoop是一种开源的分布式计算软件框架,适用于大规模计算和数据处理,目前已成为云计算和大数据处理的标准工具。
分布式计算架构设计与实现

分布式计算架构设计与实现随着人工智能、大数据、物联网等新技术的发展,计算机系统面临着越来越大的数据量和复杂的计算任务。
传统的计算机架构已经不足以满足需求,分布式计算架构应运而生。
本文将探讨分布式计算架构的设计与实现。
一、分布式计算架构的概念分布式计算架构是指一个由多个计算机协同工作组成的计算环境,分布式计算系统中的计算机节点互相通信,相互协作,共同完成一个计算任务。
与传统的集中式计算环境相比,分布式计算系统具有如下优点:1.可靠性高:由于分布式计算系统中每个节点都是相互独立的,当其中的一个节点出现故障时,其他节点仍然可以正常工作。
因此,分布式计算系统有更高的可靠性。
2.灵活性好:分布式计算系统可以根据需要动态添加或删除计算节点,从而适应不同规模和需求的计算任务。
3.处理能力强:由于分布式计算系统可以在多个计算节点同时工作,其处理能力也相应增强。
4.可扩展性强:分布式计算系统可以通过增加节点数量来提高系统的整体性能。
二、分布式计算架构的设计分布式计算架构的设计是一个复杂的过程,需要考虑很多因素。
下面介绍一些常用的分布式计算架构设计模式。
1.客户端-服务器架构客户端-服务器架构是最常用的分布式计算架构之一,它将计算任务分成客户端和服务器两个部分。
客户端向服务器发出请求,服务器根据所收到的请求来进行计算,并将计算结果返回给客户端。
客户端-服务器架构可以降低系统的复杂性,提高系统的可靠性和安全性。
但是,由于服务器要承担所有计算任务,如果客户端数量过多,服务器负载会变得非常大,导致系统性能受到影响。
2.对等网络架构对等网络架构是一种去中心化的分布式计算架构。
在对等网络架构中,每个节点都是对等的,它们之间相互通信,共同完成计算任务。
对等网络架构的优点是可以充分利用每个节点的计算能力,当其中的一个节点出现故障时,其他节点仍然可以正常工作。
但是,对等网络架构的缺点是系统的设计和管理比较困难。
3.基于消息传递的架构基于消息传递的架构是一种基于消息传递的分布式计算架构。
分布式文件系统设计与实现实验报告

分布式文件系统设计与实现实验报告引言:分布式文件系统是指将存储在不同物理位置的文件以一种透明、统一的方式组织起来,使用户能够像访问本地文件一样方便地对其进行存取。
本实验旨在设计和实现一个分布式文件系统,通过研究其原理和算法,探索其在分布式计算环境下的性能和可扩展性。
设计与实现:1. 架构设计1.1 主从架构1.2 对等架构1.3 混合架构2. 文件分配算法2.1 随机分配算法2.2 基于哈希的分配算法2.3 基于一致性哈希的分配算法3. 数据一致性管理3.1 副本机制3.2 一致性协议4. 容错与恢复4.1 容错机制4.2 数据恢复算法5. 性能优化5.1 负载均衡策略5.2 数据缓存技术实验过程与结果:在实验中,我们选取了对等架构作为设计的基础。
首先,我们搭建了一个由多台计算机组成的分布式系统,并在其上安装了相应的操作系统和软件环境。
然后,我们根据设计与实现的要求,编写了相应的代码,并进行了测试和优化。
实验结果表明,我们设计与实现的分布式文件系统具有较好的性能和可扩展性。
通过合理的文件分配算法和一致性管理策略,我们实现了文件的快速存取和数据的一致性维护。
同时,通过容错与恢复机制,我们提高了系统的可靠性和稳定性。
此外,我们还采用了负载均衡和数据缓存等技术,有效地优化了系统的性能。
结论:本实验的设计与实现进一步深化了对分布式文件系统的理解,并验证了相关算法和策略的可行性和有效性。
通过实验过程中遇到的问题和得到的经验,我们对分布式系统的设计与实现有了更深入的认识。
未来,我们将进一步改进和扩展分布式文件系统的功能,以适应更复杂的分布式计算环境。
参考文献:[1] Tanenbaum, A. S., & Van Steen, M. (2002). Distributed systems: principles and paradigms. Pearson Education.[2] Ghemawat, S., Gobioff, H., & Leung, S. T. (2003). The Google file system. ACM SIGOPS Operating Systems Review, 37(5), 29-43.[3] DeCandia, G., Hastorun, D., Jampani, M., Kakulapati, G., Lakshman,A., Pilchin, A., ... & Vosshall, P. (2007). Dynamo: Amazon’s highly available key-value store. ACM SIGOPS Operating Systems Review, 41(6), 205-220.。
分布式数据库的设计与实现

分布式数据库的设计与实现分布式数据库是一种将数据存储在不同的物理节点上的数据库系统。
它通过将数据分散存储在多个服务器上,以实现高可用性、高性能和横向扩展等优势。
本文将介绍分布式数据库的设计与实现的方法和原则。
一、概述分布式数据库设计的目标是实现数据的分布式存储和访问,同时保证数据的一致性、可靠性和性能。
它通常可以分为两个部分:分布式数据库管理系统(Distributed Database Management System,简称DDMS)和数据分布策略。
二、DDMS设计与实现1. 数据切分在设计分布式数据库时,首先需要将数据按照一定的规则进行切分,将其分散存储在多个节点上。
常见的数据切分方法有垂直切分和水平切分两种。
- 垂直切分:按照业务模块将数据库表进行切分,使得每个节点只存储一部分表的数据。
这样可以减少单一节点的负载,提高系统性能和可用性。
- 水平切分:按照某个列或一组列的数值范围将表的数据划分成多个部分,分别存储在不同的节点上。
这样可以实现数据的负载均衡和横向扩展。
2. 数据复制在分布式数据库中,为了保证数据的可靠性和高可用性,一般会对数据进行复制存储。
常见的数据复制方法有主从复制和多主复制两种。
- 主从复制:一个节点作为主节点负责接收和处理所有的写入请求,其他节点作为从节点负责复制主节点的数据,并处理读取请求。
这样可以提高系统的读取性能和可用性。
- 多主复制:多个节点都可以处理读写请求,并相互之间进行数据同步。
这样可以提高系统的写入性能和可用性。
3. 数据一致性在分布式数据库中,由于数据的复制和分布式存储,会导致数据的一致性问题。
为了解决这个问题,可以采用一致性哈希算法来确定数据存储的位置和复制的节点。
同时,可以使用副本一致性协议来实现数据的一致性。
- 一致性哈希算法:将数据的键值通过哈希函数映射到一个统一的Hash环上,根据节点在环上的位置确定数据的存储节点。
这样可以实现动态添加和删除节点时的数据迁移。
数据库的并行处理与多线程编程技巧

数据库的并行处理与多线程编程技巧随着数据规模的快速增长和对实时性能的需求提高,数据库的并行处理和多线程编程技巧变得越来越重要。
并行处理可以提高数据库的处理速度和吞吐量,而多线程编程技巧可以充分利用多核处理器和并行处理的能力。
本文将探讨数据库的并行处理技术和多线程编程技巧,并介绍如何优化数据库的性能。
一、数据库的并行处理技术1. 并行查询并行查询是指将一个查询任务分成多个子任务并行执行,然后将结果合并返回。
数据库系统会将查询任务分解成若干个并行计算任务,并将数据划分成多个块,然后将这些块分配给多个计算节点并行处理。
并行查询能够充分利用多个计算节点和多核处理器的并行计算能力,提高查询速度。
在应用并行查询时,可以使用以下的技巧来提高并行性能:- 数据分片:将数据划分成多个部分,每个部分分配给不同的计算节点,以减少数据移动的开销,提高查询效率。
- 并行扫描:多个计算节点同时扫描不同的数据块,加快数据的读取速度。
- 并行连接:将多个数据块的连接过程分解为多个并行计算任务,加快数据连接的速度。
2. 并行写入并行写入是指将数据写入数据库时,同时将数据分配给多个写入节点并发写入。
与传统的串行写入相比,并发写入可以显著提高数据库的写入性能。
在应用并行写入时,可以使用以下的技巧来提高写入性能:- 数据分区:将数据划分成多个部分,并将每个部分分配给不同的写入节点,并行写入。
- 分布式事务处理:将事务拆分成多个子事务,每个子事务分配给不同的写入节点并行处理。
- 并发控制:使用适当的并发控制机制,避免写入冲突,提高写入性能。
二、多线程编程技巧在数据库的并行处理中,多线程编程技巧起着关键的作用。
通过使用多线程,可以充分利用多核处理器的并行计算能力,提高程序的并发性和响应性。
下面介绍一些常用的多线程编程技巧:1. 线程池线程池是一种常见的多线程编程模型,通过维护一组可重用的线程,避免了线程的频繁创建和销毁开销。
线程池可以提高程序的性能和稳定性。
threadpoolexecutor 饱和等待策略-概述说明以及解释

threadpoolexecutor 饱和等待策略-概述说明以及解释1. 引言1.1 概述线程池在多线程编程中扮演着重要的角色,它能够提供一种管理和复用线程的机制,从而减少线程创建和销毁的开销,并有效地控制系统中的线程数量。
而线程池的饱和等待策略是线程池中的一个重要概念,它决定了当线程池中的线程都被占用时,新到来的任务应该如何处理。
饱和等待策略的选择对线程池的性能和稳定性有着重要的影响。
在本文中,我们将重点探讨线程池的饱和等待策略,介绍不同的策略类型以及它们的特点和适用场景。
通过深入了解线程池的饱和等待策略,读者将能够更好地理解和应用线程池,提高程序的效率和稳定性。
接下来的章节中,我们将从线程池的概念和作用开始讲解,然后详细介绍饱和等待策略的背景和作用。
最后,我们将总结本文的主要内容,并给出线程池饱和等待策略的应用场景,以及未来可能的发展方向。
通过本文的学习,读者将能够全面了解线程池的饱和等待策略,在实际开发中做出明智的选择,并能够根据实际需求进行适当的优化和调整。
希望本文能够对读者有所启发,并对多线程编程有所帮助。
1.2 文章结构本文将从引言、正文和结论三个部分展开讨论threadpoolexecutor 的饱和等待策略。
具体的章节安排如下:引言部分将对文章的主题进行简要介绍,包括线程池和饱和等待策略的概念以及文章的目的。
正文部分分为三个章节,分别介绍了线程池的概念、饱和等待策略的介绍和线程池饱和等待策略的分类。
在2.1节中,将对线程池的定义、作用和基本原理进行阐述,帮助读者全面了解线程池的基本知识。
在2.2节中,将详细介绍threadpoolexecutor的饱和等待策略,并解释其作用和原理。
在2.3节中,将对线程池的饱和等待策略进行分类,介绍不同的策略以及各自的特点和适用场景。
结论部分将对整篇文章进行总结,并从应用场景和未来展望两个方面进行讨论。
在3.1节中,将对文章的主要观点和论述进行总结,让读者对threadpoolexecutor的饱和等待策略有一个清晰的概括。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
分布式计算中多队列线程池的设计与实现摘要:随着网络和分布式计算的日益发展,应用程序及其处理的数据的规模也在不断增加。
如何保证分布式计算环境下,往往不同的计算任务使用不同的计算资源,如何提高服务器集群整体的吞吐率和运行效率,是构建此类应用时面临的较为棘手的问题。
使用对不同计算资源进行分别处理的方法,设计并实现一种高效的多队列线程池,针对分布式计算环境做进一步的改进,并对其进行性能分析。
这种方法已经应用到某协同计算平台的实现中,并取得了很好的效果。
关键词:分布式计算线程池多线程任务迁移优先级队列中图分类号:tp393.05 文献标识码:a 文章编号:1007-3973(2013)004-095-041 引言随着网络和分布式计算的发展,应用程序程序及其处理的数据的规模也在不断增加,单个应用节点已经很难快速处理海量的数据。
很多大型应用都采用分布式模式来处理其业务逻辑和数据信息。
在这种情况下,每时每刻都有大量的请求到达应用服务器等待处理。
如何在客户请求数量迅速增长的情况下,保持高效的吞吐率并让每个客户得到满意的服务性能,是一个亟待解决的问题。
线程池技术的出现为这一类问题提供了解决方法。
由于线程是比进程更轻巧的程序调度单位,因而比进程更少耗费资源。
另外,由于线程池中始终保证了一定数量的工作线程的存在,因此服务器端尽可能地减少了创建和销毁对象的次数,特别是一些很耗费资源的对象的创建和销毁。
然而传统的线程池技术使用唯一的工作队列来保存需要处理的任务,导致了对于竞争不同计算资源的可并行处理的任务之间不能进行有效的调度,从而影响了系统的吞吐率和服务器集群整体的运行性能。
在本文实现所处的分布式计算环境下,为了提高服务器集群的并发度,设计并实现了一种多队列线程池,采用了对不同计算资源分别进行处理的方式,将需要使用不同计算资源的任务发送到不同的任务队列上。
保证了对于不同计算资源的并行处理,极大地保证了服务器集群整体的运行性能和应用服务器的吞吐率。
本文按如下方式组织:第2节介绍线程池技术的基本原理;第3节介绍多队列线程池的设计和实现;第4节是性能测试数据和分析;最后是全文的小结。
2 传统线程池技术基本原理与不足2.1 传统线程池技术原理在传统的线程池技术出现之前,应用服务器往往需要对每个任务创建一个线程,并由这个线程负责该任务的执行。
这种方法导致了大量线程的产生,比如当应用服务器上客户端提交了数量庞大的运行时间较短、各自独立的任务时,服务器端将不断创建和销毁大量的线程,这势必会造成系统资源的耗尽。
传统线程池技术使用共用工作队列的方法,解决了上述每个任务都创建线程的方法带来的问题。
传统线程池技术使用一个共用的工作队列和一个线程池来利用底层的硬件提供的并发性,对计算任务进行处理。
如图1所示,服务器应用使用一个共用的工作队列来存放从客户端提交的计算任务。
线程池中所有的工作线程,从共用的工作队列中检索任务并执行任务直至完成。
如果工作队列中没有任务的话,线程就阻塞在队列上。
代码1提供了一个传统的使用共同工作队列的线程池的简单实现。
图1 共用工作队列线程池代码1. 共用工作队列线程池简单实现/* 定义共用的工作队列和线程池来执行客户端提交的任务 */ public class simpleworkqueue {private final poolworker[] threads;private final blockingdeque queue;public simpleworkqueue(int nthreads){queue = new linkedblockingdeque();threads = new poolworker[nthreads];for (int i=0; ithreads[i] = new poolworker();threads[i].start();}}/* 内部工作线程类,用来执行远程任务 */ private class poolworker extends thread {/** 方法从工作队列中检索任务并开始执行任务* 如果队列中没有任务的话线程将等待*/public void run() {while (!stopnow) {try {runnable r = (runnable) queue.takelast();r.run();} catch ( ng.throwable e) { }}}}}2.2 传统线程池技术的不足(1)工作线程之间的竞争。
由图1我们可以看出,线程池中一定数量的工作线程,共同竞争共用工作队列上的任务。
这就需要在工作队列的实现时,考虑各个工作线程之间的同步机制,为工作队列设计带锁的数据结构是一种解决方法。
但是这无疑增加了编程的复杂度和系统运行期死锁的概率。
因此传统的线程池技术并不能避免或者隔离线程池中多个工作线程之间的竞争。
(2)不能定义任务优先级。
由于系统共用一个工作队列,因此由客户端提交的计算任务不能定义任务的优先级。
所有计算任务将被统一的在工作队列中排队,按照先来先服务的方法进行调度执行。
此时,即使客户端有优先级级别较高的计算任务需要执行,也只能排队等待工作队列中排在前面的计算任务先执行完毕,才能够调度执行。
这势必会造成客户端响应的延迟和用户使用的友好性。
3 多队列线程池设计与实现3.1 多队列线程池基本原理与实现如图2所示,我们设计了一种每个工作线程一个工作队列(queue-per-thread)的方法--以此来隔离工作线程之间的竞争,并针对使用不同计算任务和具有不同优先级的任务在不同的工作队列中进行排队。
如图2所示。
图2 queue-per-thread线程池在这一方法中,每个线程都有自己的工作队列,一般情况下一个工作线程只能从自己的队列而不能从任何的其他队列中检索任务。
该方法隔离了检索任务时的竞争,因为这种情况下不存在其他要和它争夺任务的线程。
这一做法保证了如果工作队列中有任务存在的话,线程就不会进入睡眠状态,这样就有效地利用到了应用服务器的多核cpu等硬件资源。
代码2展示了如何很容易地从共用工作队列方法迁移到每个线程一个队列方法上,只需对代码1展示的代码做几处修改就可以了。
在代码2中,构造函数在启动时初始化了多个队列(等于线程的数目),每个线程都维护一个名为thread_id的id。
接着,thread_id 被用来隔离竞争,其帮助每个线程从自己的队列中检索任务。
代码2. queue-per-thread线程池实现代码/* 修改成多个队列的初始化*/for (int i=0; i();}........./* 任务检索的修改 */r = (runnable) queue[thread_id].takelast();3.2 优先级队列及队列间任务迁移虽然每个线程一个队列这种方法极大地减少了竞争,但它并不能保证优先级高的任务首先执行完毕,并且不能保证底层的多核在所有时候都能够被有效利用。
例如,如果有一两个队列比其他队列先变空了的话会有什么事情发生呢?这是一种常见的情况,在这种情况下,只有少数的线程在执行任务,而其他的线程(队列已空的线程)则在等待新任务的到来。
这种情况是可能发生的,理由如下:(1)调度算法的不可预测性。
(2)传入计算任务的不可预测性(优先级别和执行时间的长短)我们为解决上述问题设计了一种任务迁移的方法。
首先,我们设置了不同任务队列的优先级,使得具有不同优先级的任务将被提交到不同优先级的队列中。
其次,我们设计了不同优先级的任务队列之间的任务迁移策略。
这分为两种情况:(1)当一个线程发现有比自己的队列更高优先级的任务队列中有任务时,工作迁移方法让该线程从较高优先级队列中迁移工作。
这种做法确保了较高优先级的任务队列比较低优先级的队列首先执行完毕。
(2)当线程发现自己的任务队列变空时,工作迁移方法将让该线程从较低优先级队列中迁移工作。
这种做法保证了线程(对应cpu核数)每时每刻都是忙碌的。
图3展示了这两种场景,当线程2发现有较高优先级的队列(队列1)中存在任务时,将从线程1的队列中获取了一个工作任务。
当线程1发现自己的任务队列为空,将从线程2的优先级较低的任务队列中迁移工作。
为了防止任务迁移过程中可能产生过多的竞争,我们使用一个双端队列来作为任务队列的实现,理由如下:(1)只有工作线程才能访问它自己的双端队列的头端,因此双端队列的头端永远也不会存在竞争。
(2)双端队列的尾端只有在线程已经运行完所有的工作时才会访问到,因此任何线程的双端队列的尾端也都很少有竞争出现。
图3 任务迁移策略代码3说明了如何从其他的队列中获取工作任务,只需要对每个线程一个队列方法做几处修改就可以了。
这种情况下,每个线程都调用polllast()而不是takelast()方法来从队列中获取任务,从而保证了当队列中没有任务时,工作线程不会在自己的队列上阻塞。
一旦线程发现有别它的队列较高优先级的队列中存在计算任务的话,它就通过调用该线程队列的pollfirst()来从其他队列中获取工作任务。
并且当线程发现自己的队列为空时,就使用同样的方法从较低优先级任务队列中获取任务。
清单3. 实现工作迁移/* 查找比thread_id小的具有较高优先级队列中是否存在任务,并从中获取一个 */r = (runnable)transportworkfromhigh(thread_id);/* 执行自己的任务队列中的任务*/if(null == r) {r = (runnable) queue[thread_id].polllast();}if(null == r) {/*查找比thread_id大的具有较低优先级队列中是否存在任务,并从中获取一个 */r = transportworkfromlow(thread_id);}/* 从较高优先级队列中获取任务的方法 */runnable transportworkfromhigh (int index) {for (int i=0; ifor (int i=index+1; i<=queue.length (); i++) {object o = queue[i].pollfirst();if(o!=null) {return (runnable) o;}}return null;}4 性能测试分析为了验证带工作迁移的多队列线程池的性能,我们设计了一个小型的测试方案并记录了测试结果。
这一测试的基本工作是创建大量的10x10矩阵乘法运算任务(为了测试方便,将所有的任务优先级设为相同)并使用基本线程池及带工作迁移的多队列线程池来执行它们。
我们在实验室的工作站机器上对上述方法进行了测试,结果非常乐观。