CN110597606A - 一种高速缓存友好的用户级线程调度方法 - Google Patents
一种高速缓存友好的用户级线程调度方法 Download PDFInfo
- Publication number
- CN110597606A CN110597606A CN201910745905.4A CN201910745905A CN110597606A CN 110597606 A CN110597606 A CN 110597606A CN 201910745905 A CN201910745905 A CN 201910745905A CN 110597606 A CN110597606 A CN 110597606A
- Authority
- CN
- China
- Prior art keywords
- task
- thread
- worker
- user
- readylist
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/48—Program initiating; Program switching, e.g. by interrupt
- G06F9/4806—Task transfer initiation or dispatching
- G06F9/4843—Task transfer initiation or dispatching by program, e.g. task dispatcher, supervisor, operating system
- G06F9/4881—Scheduling strategies for dispatcher, e.g. round robin, multi-level priority queues
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/50—Allocation of resources, e.g. of the central processing unit [CPU]
- G06F9/5005—Allocation of resources, e.g. of the central processing unit [CPU] to service a request
- G06F9/5011—Allocation of resources, e.g. of the central processing unit [CPU] to service a request the resources being hardware resources other than CPUs, Servers and Terminals
- G06F9/5016—Allocation of resources, e.g. of the central processing unit [CPU] to service a request the resources being hardware resources other than CPUs, Servers and Terminals the resource being the memory
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/50—Allocation of resources, e.g. of the central processing unit [CPU]
- G06F9/5005—Allocation of resources, e.g. of the central processing unit [CPU] to service a request
- G06F9/5027—Allocation of resources, e.g. of the central processing unit [CPU] to service a request the resource being a machine, e.g. CPUs, Servers, Terminals
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F2209/00—Indexing scheme relating to G06F9/00
- G06F2209/50—Indexing scheme relating to G06F9/50
- G06F2209/5011—Pool
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F2209/00—Indexing scheme relating to G06F9/00
- G06F2209/50—Indexing scheme relating to G06F9/50
- G06F2209/5018—Thread allocation
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Memory System Of A Hierarchy Structure (AREA)
- Information Retrieval, Db Structures And Fs Structures Therefor (AREA)
Abstract
本发明提供了一种高速缓存友好的用户级线程调度方法,所述方法是一种将用户级线程映射到物理线程的用户级线程调度方法。每个物理线程对应一个存放由任务派生的子任务容器对象池Arena,与一个用于存放用户通过外部接口新增任务的容器Buffer,物理线程优先执行对象池Arena中的本地任务,在执行完后不陷入睡眠,而是主动窃取其他物理线程对象池Arena中的任务,若不存在对象池Arena中的任务则执行Buffer中的新任务。该方法的新颖之处在于将无锁任务容器与内存池、FreeList统一在一个数据结构中,避免了频繁的任务构造函数调用,此外还将所有任务固定分配在相邻且Aligned的内存区域,因此可更有效地利用CPU高速缓存。
Description
技术领域
本发明涉及一种高速缓存友好的用户级线程调度方法。
背景技术
用户级线程池是新兴服务端语言中广泛采用的语言特性,如goroutine。相比传统线程,它并不会提升性能,但能更好地将程序逻辑与物理线程约束之间的耦合消除,从而产生更灵活的超高并发的编程范式。
传统线程池的一个典型实现方式是若干个工作线程从一个共享的任务队列中取出任务再执行。
传统线程池的缺陷之一是一个线程执行完毕后会陷入睡眠,等到线程池的主线程分配任务给它,这个陷入睡眠再获取任务的过程对并发性能造成了不必要的损失。因此在此之上衍生出了一种更有效的work-stealing算法。每个工作线程维护独立的任务队列,一旦执行完自己的任务,不会陷入睡眠,而是主动从其他工作线程窃取任务。传统线程池的另一个缺陷是任务生成的子任务进入唯一共享队列的并发性能差。Work-stealing算法中每个物理线程拥有独立的任务队列,这个任务队列用特殊的无锁数据结构实现,能够高并发地加入、取出新的子任务。
传统线程池的缺陷之三是子任务执行顺序与线性执行顺序不符,cache(CPU高速缓存)的temporal locality(时序局部性)较差(越新生成的子任务越应该优先执行,而非相反)。Work-stealing算法同样通过优先取新生子任务的方式更好的利用了cache的temporal locality。
现有的Work-stealing算法在实践中仍存在以下问题:
1、子任务递归产生的场景下,频繁地创建、销毁任务存在较高的内存分配与任务对象构造开销。
2、任务对象的物理内存布局可能是相对零散的,且不一定是cache-line aligned(缓存行对齐)的。因此导致cache效率不佳。
发明内容
发明目的:本发明所要解决的技术问题是针对现有技术的不足,提供一种高速缓存友好的用户级线程调度方法,所述方法是一种将用户级线程映射到物理线程的用户级线程调度方法。每个物理线程对应一个用户级线程容器,物理线程按照一定顺序进行任务执行,本发明具体包括如下步骤:
步骤1,线程池初始化;
步骤2,线程池运行,进行用户级线程调度。
步骤1包括如下步骤:
步骤1-1,根据cpu数目确定工作线程Worker数目,每个工作线程Worker对应一个物理线程,工作线程Worker中包含对象池Arena;
步骤1-2,初始化每个工作线程Worker的对象池Arena(对象池内含预先构造好的用户级任务对象),预先构造对象池Arena中的FixSizedTask,FixSizedTask是内存中固定大小的用户级任务的具体实现的抽象,对用户不可见,属于底层实现的一个组件;
步骤1-3,初始化对象池Arena中的4个链表:ExecList,FreeList,ReadyList,StolenList,其中FreeList中装满预先构造好的Task和join方法,所述join方法即等待子任务,并与子任务同步的方法;FreeList的底层功能由FixSizedTask实现,从而节省运行时构造时间;
Task是任意用户级任务的任务例程的抽象,是公开给用户的接口,由用户自主定义任务执行函数,并提供fork方法(即产生子任务的方法,所谓子任务就是和当前任务有一样的类型,可能有不同参数的新的任务。递归算法中需要使用该方法)。
ExecList是专门存放即将执行或正在执行中的FixSizedTask的容器,其中的FixSizedTask不能被其他工作线程窃取;
FreeList是专门存放预先构造好的空的FixSizedTask的容器,新任务创建时能够随时取用,任务执行完要回收到该容器;
ReadyList是专门存放待执行的FixSizedTask的容器,其中的FixSizedTask是能够被其他工作线程窃取的;
StolenList是专门存放已经被其他工作现场窃取的FixSizedTask的容器,这些FixSizedTask虽被窃取,物理上仍位于本地对象池Arena的FixSizedTask中,因此被窃取的只是抽象的所有权。StolenList必须维护这些被窃取任务的信息,以便将来这些任务结束再将其回收到本地的FreeList中去;
步骤1-4,将所述对象池Arena的所有FixSizedTask中的任务指针加入所述对象池Arena的FreeList中;
步骤1-5,初始化用于暂存用户提交的任务的Buffer,Buffer是Task的缓存区,专门存放由用户提交的Task,而非fork方法产生的子任务Task。
步骤1-1中,所述工作线程Worker对应一个物理线程,持有一个Buffer和一个对象池Arena;工作线程Worker在闲暇时会自适应地进行休眠。
所述对象池Arena为对应工作线程Worker拥有的子任务的任务容器,由ExecList,ReadyList,FreeList,StolenList和FixSizedTask组成;ExecList,ReadyList,FreeList,StolenList只存放FixSizedTask指针,用于进行空闲对象管理,兼具内存池和预构造对象池的功能。
步骤1-3中,所述ExecList,FreeList,ReadyList,StolenList均为无锁栈数据结构,支持无锁的并发push(入栈操作,基础的计算机科学术语)与pop(出栈操作,计算机科学术语)操作,其中ReadyList和StolenList是ABA-prone(免疫ABA问题,所谓ABA问题的定义可参照wiki,简单举例来说就是无锁并发数据结构在一个线程取出A后,存入B,然后再存入A,另一个线程查看该结构,发现A仍是最新的元素,误以为该数据结构未经其他线程改动)的,即必须保证能够解决ABA问题,FreeList和ExecList的使用场景中永远不会出现ABA问题,因此放宽约束,可以使用更简单的无锁栈实现方式。
步骤1-5中,所述任务在物理上顺序存放于预先构造好的Task中,FreeList,ReadyList,StolenList,ExecList只存放Task的指针;
所述任务有如下共同的元数据:
next指针;
用于解决ABA问题的引用计数器refcnt(可选),引用计数器refcnt是解决ABA问题所需的额外变量。当然存在其他解决ABA问题的途径,可能不需要它,也可能需要另外的数据支持,这只是一种可能的解决方案;
用于统计未结束的子任务数量的依赖计数器pendingcnt;依赖计数器,用于统计当前任务尚未结束的子任务的总数目,数目为0,则当前任务的join方法可停止等待,继续执行下去;
父任务指针parent;
每个工作线程Worker有个从0开始递增的序号,即工作线程WorkerID,以位图形式表示工作线程WorkerID和location的状态字段state,location是一个数字,用于代表所述任务位于哪个容器,有以下几种可能:FreeList,ReadyList,ExecList,StolenList,本地线程的运行栈,Buffer的空闲区间,Buffer的可用区间,Buffer的被窃取区间(location可以取值1~8分别对应上述容器);
用于同步的synced字段。具体的任务由用户客制,但大小必须严格小于一个固定的值。这个值是可配置的,但必须是cache-line size的整数倍,如果任务体积普遍很小,可以选择64B,稍大一些选择128B,256B等。
所述Buffer为对应工作线程Worker所拥有的用户任务暂存容器。
步骤2包括如下步骤:
步骤2-1,工作线程Worker初始化(在工作线程Worker构造函数执行时,进行工作线程的初始化,初始化过程即加载工作线程的执行例程函数,构造出线程对象),工作线程一开始是睡眠状态;
步骤2-2,用户调用start(start是公开给用户的线程池接口方法,调用它即标志着线程池真正开始运行,此前初始化后线程会立刻陷入睡眠,真正运行后这些线程都会被唤醒)正式唤醒所有工作线程,start只能在所有工作线程Worker初始化完成之后调用;
步骤2-3,工作线程Worker会优先从ExecList中按照FIFO(计算机科学术语,先进先出)顺序选取任务执行,ExecList中的任务本身就处于正在执行状态,只是暂存于ExecList中,ExecList中的任务优先级最高,数目较少(因为只有最新生成的子任务,或用户指定的高优先级子任务会被直接放入ExecList),且只会被所述工作线程Worker执行,永远不会被其他工作线程窃取;如果选取任务成功则跳转到步骤2-9,否则执行步骤2-4;
步骤2-4,从ReadyList中取出任务,即调用ReadyList的pop方法,取出最新放入ReadyList的任务,优先取出最新的任务的好处是可利用CPU高速缓存的局部性,或者通俗地说,热度,从而提高性能,ReadyList中的任务既能够被本地工作线程取走,也能够被其他工作线程窃取;如果选取任务成功则跳转到步骤2-9,否则执行步骤2-5;
步骤2-5,从其他工作线程Worker的ReadyList窃取任务(窃取任务也是调用ReadyList的pop方法,取出最新的任务,原因同步骤2-4),如果取任务成功则跳转到步骤2-9,否则执行步骤2-6;
步骤2-6,继续尝试窃取下一个工作线程Worker,直到遍历所有工作线程Worker都失败或成功,取任务成功则跳转到步骤2-9;
步骤2-7,若所有窃取失败,则从本地Buffer取新的任务,取任务成功则跳转到步骤2-9,否则执行步骤2-8;
步骤2-8,从其他工作线程Worker的Buffer处取任务,如果取任务失败则进行空闲判定,若空转时间大于空转时间最大值则陷入休眠(由用户配置空转时间最大值,取决于用户对该线程池超高CPU占用率的容忍程度。如果空转时间最大值较低,则线程池会较快地陷入睡眠,放弃CPU占用,但如果这种空闲只是假象,很快又有新的任务,反而会导致性能下降。因此用户可以根据自己的实际需求进行配置),否则返回步骤2-3;如果取任务成功则进行步骤2-9;
步骤2-9,执行任务,根据任务本身的逻辑将新生的子任务放入ReadyList或ExecList,任务和子任务全部执行完后更新父任务(若存在)状态,让pendingcnt减1,若pendingcnt为0则将父任务标记为终结,若父任务是用户提交的阻塞任务,则唤醒用户线程,最后跳转至步骤2-3。
本发明所述方法涉及到下列几种数据结构的设计:。
1、Pool(Pool就是本发明描述的对象,一个用户级线程池,是一切数据结构的总和,同时提供用户接口):对应一个用户级线程池。
2、工作线程Worker:对应一个物理线程,持有一个Buffer和一个对象池Arena。它在闲暇时会自适应地进行休眠。在运行时会先试图从本地ExecList中取任务执行,失败后从ReadyList中取任务执行,失败后从其他物理线程对应的工作线程Worker的对象池Arena中窃取入任务,再失败则从本地Buffer中取出任务,再失败则从其他物理线程对应的工作线程Worker的Buffer中窃取任务。
3、对象池Arena:对应工作线程Worker拥有的子任务的任务容器,由ExecList,ReadyList,FreeList,StolenList和FixSizedTask组成。ExecList,ReadyList,FreeList,StolenList只存放FixSizedTask指针,用于进行空闲对象管理,兼具内存池和预构造对象池的功能。
4、Buffer:对应工作线程Worker所拥有的用户任务暂存容器。
5、PrivateStack:无需解决ABA问题的无锁Stack数据结构。
6、ABAProneStack:能够解决ABA问题的无锁Stack数据机构。
7、FixSizedTask:对应一个任务在内存中具体的布局形式,所有任务都有一个固定的元数据头,其中包含任务通用的各种状态,以及指向父任务的指针。
本发明具有如下有益效果:
1、大幅提高递归任务(任务本身产生子任务,子任务与父任务的例程一样,因此也会产生子任务,以此类推,直到满足某个条件才终止分裂)的性能(性能是对执行任务所需时间长短的度量,时间越短性能越高)。
2、平台兼容性好。本发明描述的方法不依赖任何平台特定的指令,不依赖特殊硬件,是可以在任意操作系统上移植的算法。
附图说明
下面结合附图和具体实施方式对本发明做更进一步的具体说明,本发明的上述和/或其他方面的优点将会变得更加清楚。
图1是本发明的线程池初始化流程示意图。
图2是本发明的线程池运行流程示意图。
图3是本发明的线程池组件图。
具体实施方式
如图1所示,本发明的线程池初始化的实现如下:
步骤一,根据cpu数目确定工作线程Worker数目。例如在16核机器上,工作线程Worker数目即为16。
步骤二,初始化每个工作线程Worker的对象池Arena,预先构造对象池Arena中的FixSizedTask数组,该数组大小是可配置的,用户应根据硬件与软件的内存约束和并发性能需求自行选定合适的值,数值越大,则内存开销越大,但相应地并发性能也会越好。在本发明的一个具体实现github.com/wjp-release/cfscheduler中使用的Arena内FixSizedTask数组大小为1048576,即2^20,单个工作线程占用内存为128MB。构造好的FixSizedTask的各个字段的默认取值必须完全符合如下规格:synced为false(计算机科学中的布尔值,表示假,非真),state中的location为0(代表处于FreeList),state中的WorkerID为当前线程的数字序号,parent为nullptr(nullptr为指针取值,表示空指针),refcnt为0,next为nullptr(表示尚未加入步骤三中任意一个链表,当加入链表后,next才会指向链表中下一个FixSizedTask)。
步骤三,初始化对象池Arena中的4个链表:ExecList,FreeList,ReadyList,StolenList。4个链表初始化后都为空链表。
步骤四,将所述对象池Arena的所有FixSizedTask中的任务指针加入该对象池Arena的FreeList中。按照数组下表顺序全部连接在FreeList链表中,表示这些预先构造的任务都处于闲置可用状态。此时,FreeList包含了FixSizedTask数组中的所有FixSizedTask。其他3个链表仍为空,这是合理的,表示尚无准备执行的任务。
步骤五,初始化用于暂存用户提交的任务的Buffer。与Arena类似,Buffer也包含FixSizedTask数组,数组大小也由用户决定。但它的大小并不影响递归任务的并发性能,只限制了用户提交任务的速率。因此用户需根据用户提交任务速率决定Buffer里FixSizedTask数组的大小。在本发明的一个具体实现github.com/wjp-release/cfscheduler中使用的Buffer内FixSizedTask数组大小为64,比Arena的小得多,事实上即使将这个值设为1也可以,因为它的取值完全不影响单次递归任务性能测试。实际应用场景中若用户需高频提交任务,可适当增加Buffer内FixSizedTask数组大小。用户需注意,通常情况下,用户提交的任务的频率远低于递归任务产生子任务的频率,Buffer内FixSizedTask数组大小远小于Arena内FixSizedTask数组大小往往是合理选择。
如图3所示是本发明的线程池组件图,图中LogicalTask即为用户接口Task的某个子类,由用户自己定义其执行例程。
用户提交任务到本发明的线程池的实现如下:
步骤a1,通过Pool提供的接口创建自定义任务,例如ParallelSum任务(将数组等分成两半,再生成2个子任务分别处理这两半)。在github.com/wjp-release/cfscheduler/include目录下有一个parallel_sum.h文件实现了ParallelSum类。该类即定义ParallelSum任务的类,是Task类的子类,在继承基类的任务功能的基础上,还额外具备自身的3个数据段:begin指针(指向目标数组的开始),end指针(指向目标数组的结束),sum指针(指向的内存区存放本任务未来要计算出来的目标数组各元素之和)。ParallelSum类重写Task基类的compute函数(纯虚函数,专门供子类重写),从而定义该任务的执行例程。执行例程定义如下:“先计算出数组中点指针,记作mid,再用Task基类提供的fork方法生成两个ParallelSum任务。再定义两个变量x和y用于存储子任务的计算结果。第一个子任务的begin为mid,end仍为当前的end,sum指向x。第二个子任务的begin为当前的begin,end为当前的mid,sum指向y。随后调用Task基类提供sync方法等待两个子任务都执行完毕。等待结束后,将x和y相加即得到当前任务的计算结果,将其存入sum。”
步骤a2,通过Pool提供的接口提交ParallelSum任务,将这个任务放入Buffer。
用户可在Pool初始化后的任意时间提交任务(当然不可能在Pool还未初始化之前,因为两个步骤都依赖Pool提供的接口),无论Pool是否在运行中。
如图2所示,本发明线程池运行实现方式如下:
步骤一,工作线程Worker初始化时,工作线程初始化,但一开始是睡眠状态。
步骤二,用户调用start正式唤醒所有工作线程,start只能在所有工作线程Worker初始化完成之后调用。
步骤三,工作线程会优先从ExecList中按照FIFO顺序选取任务执行。这些任务本身就处于正在执行状态,只是暂存于ExecList中。它们最高优先级,数目较少(因为只有最新生成的子任务,或用户指定的高优先级子任务会被直接放入ExecList),且只会被所述工作线程执行,永远不会被其他工作线程窃取。取任务成功则跳转到步骤九。
步骤四,若ExecList取任务失败,则从ReadyList中取任务。ReadyList中的任务既可被本地工作线程取走,也可能被其他工作线程窃取。一般子任务生成后落入ReadyList。取任务成功则跳转到步骤九。
步骤五,若ReadyList取任务失败,则从其他工作线程Worker的ReadyList窃取任务。取任务成功则跳转到步骤九。
步骤六,若窃取失败,则继续尝试窃取下一个工作线程Worker,直到遍历所有工作线程Worker都失败或成功。取任务成功则跳转到步骤九。
步骤七,若所有窃取失败,则从本地Buffer取新的任务。取任务成功则跳转到步骤九。
步骤八,若本地Buffer取任务失败则从其他工作线程Worker的Buffer处取任务。全部失败则进行空闲判定,若空转时间太长则陷入休眠,否则回归步骤三继续尝试。若取任务成功则进行步骤九。
步骤九,执行任务,根据任务本身的逻辑将新生的子任务放入ReadyList或ExecList,全部执行完后更新父任务(若存在)状态,让pendingcnt减1,若pendingcnt为0则将父任务标记为终结,若父任务是用户提交的阻塞任务,则唤醒用户线程。最后跳转至步骤三。以ParallelSum任务为例,在这一步会先将它的目标数组A等分成K、L两个数组,再创建两个分别以K、L为目标数组的子任务,并将这两个子任务放入ReadyList或ExecList。然后当前任务会调用Task提供的join方法等待它的两个子任务执行结束。如果两个子任务最终执行结束,意味着当前任务的所有子孙任务都终结,pendingcnt降为0,当前任务可继续执行。对于ParallelSum任务来说,继续执行并没有额外的事情要做,因为所有实质性的并发求和工作都被子孙任务完成了,于是直接结束。当前任务结束后线程池会将当前任务的父任务的pendingcnt减1。若父任务的pendingcnt也降为0,类似地,也会将父任务的父任务的pendingcnt减1,直到最高层的任务(即用户提交的最初的那个ParallelSum任务,一切子任务的始祖)pendingcnt为0时,唤醒等待该任务的用户线程。本发明方法可稳定超过C++标准库的std::async函数。测试代码和benchmark(基准测试)参见github.com/wjp-release/cfscheduler(其中包括对本发明的代码实现,包含安装说明、测试代码与性能基准测试,开箱即用)。使用的测试任务取自cppreference.com(C++语言文档网站)的官方示例:ParallelSum,将一个数组上的数字进行并行递归分治求和,是一个典型地测试线程池性能的应用场景,计算量极轻,几乎所有开销都反应在线程调度上,可非常准确地反应线程池性能。这个任务求和的目标数组越大(相应地任务划分的子任务总数越多),则该方法比std::async领先得越多,最后甚至达到3000倍。
本发明提供了一种高速缓存友好的用户级线程调度方法,具体实现该技术方案的方法和途径很多,以上所述仅是本发明的优选实施方式,应当指出,对于本技术领域的普通技术人员来说,在不脱离本发明原理的前提下,还可以做出若干改进和润饰,这些改进和润饰也应视为本发明的保护范围。本实施例中未明确的各组成部分均可用现有技术加以实现。
Claims (8)
1.一种高速缓存友好的用户级线程调度方法,其特征在于,包括如下步骤:
步骤1,线程池初始化;
步骤2,线程池运行,进行用户级线程调度。
2.根据权利要求1所述的方法,其特征在于,步骤1包括如下步骤:
步骤1-1,根据cpu数目确定工作线程Worker数目,每个工作线程Worker对应一个物理线程,工作线程Worker中包含对象池Arena;
步骤1-2,初始化每个工作线程Worker的对象池Arena,预先构造对象池Arena中的FixSizedTask;
步骤1-3,初始化对象池Arena中的4个链表:ExecList,FreeList,ReadyList,StolenList,其中FreeList中装满预先构造好的Task和join方法,所述join方法即等待子任务,并与子任务同步的方法;
所述Task是任意用户级任务的任务例程的抽象,是公开给用户的接口,由用户自主定义任务执行函数,并提供fork方法;
ExecList是专门存放即将执行或正在执行中的FixSizedTask的容器,其中的FixSizedTask不能被其他工作线程窃取;
FreeList是专门存放预先构造好的空的FixSizedTask的容器,新任务创建时能够随时取用,任务执行完要回收到该容器;
ReadyList是专门存放待执行的FixSizedTask的容器,其中的FixSizedTask是能够被其他工作线程窃取的;
StolenList是专门存放已经被其他工作现场窃取的FixSizedTask的容器,所述FixSizedTask虽被窃取,物理上仍位于本地对象池Arena的FixSizedTask中;
步骤1-4,将所述对象池Arena的所有FixSizedTask中的任务指针加入所述对象池Arena的FreeList中;
步骤1-5,初始化用于暂存用户提交的任务的Buffer,Buffer是Task的缓存区,专门存放由用户提交的Task,而非fork方法产生的子任务Task。
3.根据权利要求2所述的方法,其特征在于,步骤1-1中,所述工作线程Worker对应一个物理线程,持有一个Buffer和一个对象池Arena;工作线程Worker在闲暇时会自适应地进行休眠。
4.根据权利要求3所述的方法,其特征在于,所述对象池Arena为对应工作线程Worker拥有的子任务的任务容器,由ExecList,ReadyList,FreeList,StolenList和FixSizedTask组成;ExecList,ReadyList,FreeList,StolenList只存放FixSizedTask指针,用于进行空闲对象管理,兼具内存池和预构造对象池的功能。
5.根据权利要求4所述的方法,其特征在于,步骤1-3中,所述ExecList,FreeList,ReadyList,StolenList均为无锁栈数据结构,支持无锁的并发push与pop操作,其中ReadyList和StolenList是免疫ABA问题的。
6.根据权利要求5所述的方法,其特征在于,步骤1-5中,所述任务在物理上顺序存放于预先构造好的Task中,FreeList,ReadyList,StolenList,ExecList只存放Task的指针;所述任务有如下共同的元数据:
next指针;
用于解决ABA问题的引用计数器refcnt;
用于统计未结束的子任务数量的依赖计数器pendingcnt;
父任务指针parent;
每个工作线程Worker有个从0开始递增的序号,即工作线程WorkerID,以位图形式表示工作线程WorkerID和location的状态字段state,location是一个数字,用于代表所述任务位于哪个容器,有以下几种可能:FreeList,ReadyList,ExecList,StolenList,本地线程的运行栈,Buffer的空闲区间,Buffer的可用区间,Buffer的被窃取区间;
用于同步的synced字段。
7.根据权利要求6所述的方法,其特征在于,所述Buffer为对应工作线程Worker所拥有的用户任务暂存容器。
8.根据权利要求7所述的方法,其特征在于,步骤2包括如下步骤:
步骤2-1,工作线程Worker初始化,工作线程一开始是睡眠状态;
步骤2-2,用户调用start正式唤醒所有工作线程,start是公开给用户的线程池接口方法,start只能在所有工作线程Worker初始化完成之后调用;
步骤2-3,工作线程Worker会优先从ExecList中按照FIFO顺序选取任务执行,ExecList中的任务本身就处于正在执行状态,只是暂存于ExecList中,ExecList中的任务优先级最高,且只会被所述工作线程Worker执行,永远不会被其他工作线程窃取;如果选取任务成功则跳转到步骤2-9,否则执行步骤2-4;
步骤2-4,从ReadyList中取出任务,即调用ReadyList的pop方法,取出最新放入ReadyList的任务,ReadyList中的任务既能够被本地工作线程取走,也能够被其他工作线程窃取;如果选取任务成功则跳转到步骤2-9,否则执行步骤2-5;
步骤2-5,从其他工作线程Worker的ReadyList窃取任务,如果取任务成功则跳转到步骤2-9,否则执行步骤2-6;
步骤2-6,继续尝试窃取下一个工作线程Worker,直到遍历所有工作线程Worker都失败或成功,取任务成功则跳转到步骤2-9;
步骤2-7,若所有窃取失败,则从本地Buffer取新的任务,取任务成功则跳转到步骤2-9,否则执行步骤2-8;
步骤2-8,从其他工作线程Worker的Buffer处取任务,如果取任务失败则进行空闲判定,若空转时间大于空转时间最大值则陷入休眠,否则返回步骤2-3;如果取任务成功则进行步骤2-9;
步骤2-9,执行任务,根据任务本身的逻辑将新生的子任务放入ReadyList或ExecList,任务和子任务全部执行完后更新父任务状态,让pendingcnt减1,若pendingcnt为0则将父任务标记为终结,若父任务是用户提交的阻塞任务,则唤醒用户线程,最后跳转至步骤2-3。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201910745905.4A CN110597606B (zh) | 2019-08-13 | 2019-08-13 | 一种高速缓存友好的用户级线程调度方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201910745905.4A CN110597606B (zh) | 2019-08-13 | 2019-08-13 | 一种高速缓存友好的用户级线程调度方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN110597606A true CN110597606A (zh) | 2019-12-20 |
CN110597606B CN110597606B (zh) | 2022-02-18 |
Family
ID=68853959
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201910745905.4A Active CN110597606B (zh) | 2019-08-13 | 2019-08-13 | 一种高速缓存友好的用户级线程调度方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN110597606B (zh) |
Cited By (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN111124651A (zh) * | 2019-12-27 | 2020-05-08 | 中通服公众信息产业股份有限公司 | 一种分布式环境多线程并发调度的方法 |
CN111782369A (zh) * | 2020-07-01 | 2020-10-16 | 浪潮云信息技术股份公司 | 一种Go语言下的数据任务处理系统及方法 |
CN113176896A (zh) * | 2021-03-19 | 2021-07-27 | 中盈优创资讯科技有限公司 | 一种基于单进单出无锁队列的随机取出对象的方法 |
CN114116155A (zh) * | 2020-08-31 | 2022-03-01 | 慧与发展有限责任合伙企业 | 无锁工作窃取线程调度器 |
CN116501475A (zh) * | 2023-06-21 | 2023-07-28 | 杭州炬华科技股份有限公司 | 线程调度方法、系统以及介质 |
CN111782369B (zh) * | 2020-07-01 | 2024-05-31 | 浪潮云信息技术股份公司 | 一种Go语言下的数据任务处理系统及方法 |
Citations (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1938686A (zh) * | 2004-03-31 | 2007-03-28 | 英特尔公司 | 提供用户级多线程操作的方法和系统 |
CN101273335A (zh) * | 2005-09-26 | 2008-09-24 | 英特尔公司 | 用户级线程的调度优化 |
US20110225372A1 (en) * | 2009-04-27 | 2011-09-15 | Lsi Corporation | Concurrent, coherent cache access for multiple threads in a multi-core, multi-thread network processor |
CN103729241A (zh) * | 2013-12-12 | 2014-04-16 | 华中科技大学 | 一种多核环境下OpenMP任务并行的优化方法 |
CN107220111A (zh) * | 2017-04-28 | 2017-09-29 | 华中科技大学 | 一种基于任务窃取的任务调度方法及系统 |
CN108920261A (zh) * | 2018-05-23 | 2018-11-30 | 中国航天系统科学与工程研究院 | 一种适于大规模并行数据处理任务的两级自适应调度方法 |
-
2019
- 2019-08-13 CN CN201910745905.4A patent/CN110597606B/zh active Active
Patent Citations (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1938686A (zh) * | 2004-03-31 | 2007-03-28 | 英特尔公司 | 提供用户级多线程操作的方法和系统 |
CN101273335A (zh) * | 2005-09-26 | 2008-09-24 | 英特尔公司 | 用户级线程的调度优化 |
US20110225372A1 (en) * | 2009-04-27 | 2011-09-15 | Lsi Corporation | Concurrent, coherent cache access for multiple threads in a multi-core, multi-thread network processor |
CN103729241A (zh) * | 2013-12-12 | 2014-04-16 | 华中科技大学 | 一种多核环境下OpenMP任务并行的优化方法 |
CN107220111A (zh) * | 2017-04-28 | 2017-09-29 | 华中科技大学 | 一种基于任务窃取的任务调度方法及系统 |
CN108920261A (zh) * | 2018-05-23 | 2018-11-30 | 中国航天系统科学与工程研究院 | 一种适于大规模并行数据处理任务的两级自适应调度方法 |
Non-Patent Citations (2)
Title |
---|
REN, YUFEI: "Design, Implementation, and Evaluation of a NUMA-Aware Cache for iSCSI Storage Servers", 《IEEE TRANSACTIONS ON PARALLEL AND DISTRIBUTED SYSTEMS》 * |
吴志强: "一种多核平台下的用户级实时多任务库", 《小型微型计算机系统》 * |
Cited By (8)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN111124651A (zh) * | 2019-12-27 | 2020-05-08 | 中通服公众信息产业股份有限公司 | 一种分布式环境多线程并发调度的方法 |
CN111124651B (zh) * | 2019-12-27 | 2023-05-23 | 中通服公众信息产业股份有限公司 | 一种分布式环境多线程并发调度的方法 |
CN111782369A (zh) * | 2020-07-01 | 2020-10-16 | 浪潮云信息技术股份公司 | 一种Go语言下的数据任务处理系统及方法 |
CN111782369B (zh) * | 2020-07-01 | 2024-05-31 | 浪潮云信息技术股份公司 | 一种Go语言下的数据任务处理系统及方法 |
CN114116155A (zh) * | 2020-08-31 | 2022-03-01 | 慧与发展有限责任合伙企业 | 无锁工作窃取线程调度器 |
CN113176896A (zh) * | 2021-03-19 | 2021-07-27 | 中盈优创资讯科技有限公司 | 一种基于单进单出无锁队列的随机取出对象的方法 |
CN116501475A (zh) * | 2023-06-21 | 2023-07-28 | 杭州炬华科技股份有限公司 | 线程调度方法、系统以及介质 |
CN116501475B (zh) * | 2023-06-21 | 2023-10-20 | 杭州炬华科技股份有限公司 | 线程调度方法、系统以及介质 |
Also Published As
Publication number | Publication date |
---|---|
CN110597606B (zh) | 2022-02-18 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN110597606B (zh) | 一种高速缓存友好的用户级线程调度方法 | |
US10331666B1 (en) | Apparatus and method for parallel processing of a query | |
KR101759266B1 (ko) | 프로세서들에 걸쳐 데이터-병렬 쓰레드들을 지닌 프로세싱 로직을 매핑하는 방법 | |
US8954986B2 (en) | Systems and methods for data-parallel processing | |
US9928109B2 (en) | Method and system for processing nested stream events | |
US9250979B2 (en) | Asynchronous grace-period primitives for user-space applications | |
US9466091B2 (en) | Atomic memory update unit and methods | |
CN106462395B (zh) | 多线程处理器架构中的线程等待 | |
US7398376B2 (en) | Instructions for ordering execution in pipelined processes | |
US8375390B2 (en) | Scheduling method and scheduling apparatus | |
EP2284703B1 (en) | Scheduling of tasks in a parallel computer system according to defined policies | |
US20030188300A1 (en) | Parallel processing system design and architecture | |
KR20180021165A (ko) | 프로세서 명령어 창에 대한 명령어 블록의 대량 할당 | |
JP2018511119A (ja) | トランザクション実行に応じて追跡データを生成する装置及び方法 | |
US11880925B2 (en) | Atomic memory update unit and methods | |
US11989816B2 (en) | Allocation of resources to tasks | |
US8959319B2 (en) | Executing first instructions for smaller set of SIMD threads diverging upon conditional branch instruction | |
US8954969B2 (en) | File system object node management | |
Dokulil et al. | Implementing the open community runtime for shared-memory and distributed-memory systems | |
CN109656868B (zh) | 一种cpu与gpu之间的内存数据转移方法 | |
JP2020107306A (ja) | マルチスレッドプロセッサの命令キャッシュ | |
CN112346879B (zh) | 进程管理方法、装置、计算机设备及存储介质 | |
KR102210765B1 (ko) | 긴 지연시간 숨김 기반 워프 스케줄링을 위한 방법 및 장치 | |
US20130166887A1 (en) | Data processing apparatus and data processing method | |
US20190310857A1 (en) | Method of Concurrent Instruction Execution and Parallel Work Balancing in Heterogeneous Computer Systems |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
CB02 | Change of applicant information | ||
CB02 | Change of applicant information |
Address after: No.1 Lingshan South Road, Qixia District, Nanjing, Jiangsu Province, 210000 Applicant after: THE 28TH RESEARCH INSTITUTE OF CHINA ELECTRONICS TECHNOLOGY Group Corp. Address before: 210007 No. 1 East Street, alfalfa garden, Jiangsu, Nanjing Applicant before: THE 28TH RESEARCH INSTITUTE OF CHINA ELECTRONICS TECHNOLOGY Group Corp. |
|
GR01 | Patent grant | ||
GR01 | Patent grant |