APP下载

隐式多线程综述

2020-01-02李劭卓

数字通信世界 2020年3期
关键词:编译器线程队列

李劭卓

(河北农业大学渤海校区,黄骅 061000)

0 引言

在计算机发展史上,计算机从单线程发展到了多线程,多线程的出现很大程度上提升了计算机的性能,但是在人类科技发展的需求以及摩尔定理的限制下,单核处理机系统已经到达极限。为了响应更多计算机性能方面的需求,适应计算机发展的需要,计算机已开始从单处理器系统向多处理器系统发展。

在多核处理机系统的快速发展中,多核系统编程(任务识别、平衡、数据分割、数据依赖、测试与调试)和程序正确性(同步与死锁)的两个方面难题越发突出。为了解决这些难题并设计出更好的多线程程序,人们开始通过编译器与运行时库来创建和管理多线程,即隐式线程(implicit threading),基于隐式线程与多线程的主要设计方法有三种:线程池(Thread pool)、OpenMP、大中央调度(Grand Central Dispatch,GCD)。

1 隐式多线程的实现方法

1.1 线程池

当多线程服务器接收到一个请求时,如果采用创建一个新的线程去处理请求会出现两种问题。第一种:创建新的线程需要时间并且在处理后会被丢失,第二种:没有限制系统内部并发执行线程的数量。这两个问题会导致系统响应速度以及性能的降低。

而线程池的出现为线程的创建、销毁以及资源不足的问题提供了解决方案。在进程开始的时候,系统就创建一定数量的线程,并将这些线程加入池中等待唤醒,当服务器收到请求时,服务器就唤醒一个可用的线程,然后将需要服务的请求传递给该线程,待线程完成服务之后,再重新返回到线程池中等待下一次唤醒,若没有可用的线程,则服务器就会开始等待,直到有空线程为止。

优点:

(1)提高了系统的响应速度。系统已经创建好了一定数量的线程,当有请求到来时,可直接使用预先建立好的线程,不需要重新创建线程,这消除了系统创建线程时的时间延迟。

(2)线程池限制了任何时刻的可用线程的数量。系统预先创建一定数量的线程,并且限制它们的数量,这能够控制线程对象在内存中的消耗。十分有利于有大量并发式访问,而其任务短小的服务器。

(3)将待执行任务从创建任务的机制中分离出来。允许使用延迟或定期执行的策略运行任务。

(4)降低系统的开销与资源的消耗。线程池中的线程被重复利用,使用后的线程会重新返回到线程池中,不会被销毁,降低了虚拟机垃圾回收方面的开销。

缺点:

(1)需要考虑线程池的大小。线程池中的线程并非越多越好,需要结合软硬件的具体环境以及应用程序自身的特点来考虑。

(2)线程泄露。当线程执行完任务后,没有返回到线程池中。需要采取异常捕捉的方法防止线程泄露。

(3)并发错误。要从逻辑上考虑线程的并发状况,防止死锁的出现。

1.2 OpenMP

OpenMP是一种支持共享内存环境的多处理器多线程并行编译语言,它由一组编译指令和API组成,其通过向C、C++、Fortran语言提供一组和平台无关的编译指令、函数调用、指导函数以及环境变量,来指示OpenMP运行时库在何时何处才能进行并行处理。

并行处理的指示指令为#pragma omp parallel,当程序进行到指示指令时,系统就会创建一个与系统处理器数量一样多的线程。原线程(主线程)与新派生出来的线程(组的从属线程)组成线程组,即从单个线程执行转换为多线程并行执行,待程序执行完并行区域(parallel fegion)的所有内容后,系统将会把并行线程的所得结果连接在一起,并重新开始单个线程执行,此通常用于循环结构的并行化处理。

除提供并行化指令外,OpenMP还允许手动设置线程数量、指定哪个数据可在线程间共享、哪个数据只属于某个线程,其支持的操作系统有Windows、Linux、Mac OS X,并可用于多种开源编译器和商用编译器。

优点:

(1)有利于多核升级后的程序性能。多核编程需要考虑到今后硬件核数升级之后的程序性能问题,如果将程序设计为随CPU核数增长,就无法固定线程的数量;如果固定线程数量并且要求CPU核数增加时,程序性能也要增加,则需要在每次硬件核数升级后,程序进行相对应的更改。OpenMP可直接根据CPU的核数创建线程,这十分方便。

(2)并行区域执行方便。多核编程中,需要将并行部分均分到各个CPU核心中,这对计算的负载均衡要求很高,但OpenMP可直接将并行区域的代码分解为多个线程执行。

(3)方便移植。OpenMP是标准规范,所有支持OpenMP的编译器执行标准一致。

缺点:

(1)使用范围有限。OpenMP是一种支持共享内存环境的多处理器多线程并行编译语言,在非共享内存系统中无法使用。

(2)高层抽象的局限性。OpenMP在需要复杂线程同步与互斥场合中不适用。

1.3 大中央调度

大中央调度是Apple Mac OS X和iOS的一种技术,它能为C语言、API和运行时库提供一组扩展,允许多个代码区域并行运行。

GCD在C与C++中增加了块(block)的扩展,用字符加{ }的形式将块括起来,同时以一个块为独立单位,然后将各个块放入调度队列(dispatchqueue)中,在执行程序时

,每次从调度队列中取出一个块,并将它分配给线程池中的一个可用线程。

调度队列有两种形式:串行(serial)和并行(concurrent)。

串行:

串行队列以先进先出的形式进行块的执行,每次只能执行一个块,每当一个块执行完后,才会从调度队列中调度下一个块。在进程中可以有多个串行队列,但是只能有一个主队列,其用于保证任务的顺序的正确性。

并行:

并发队列也以先进先出的进行块的执行,但是每次可以执行多个块,进行多个块的并行运行。

在大中央调度中的线程池由POSIX线程组成,GCD会根据应用需求以及系统的容量动态地调节线程的数量,以此实现对内部线程池的管理。

优点:

(1)GCD更加接近底层。GCD提供底层函数,在追求性能的底层操作中,速度很快,并提供更强大的控制力。

(2)系统资源利用率高。可以简单地在不同代码中传递上下文,减少上下文之间的切换,提高资源的利用率,减轻系统的负荷。

缺点:

操作实现复杂。GCD需要许多代码来实现异步操作之间的事务性、顺序行和依赖关系。

1.4 其他方法

线程构造模块(Treading Building Block,TBB):

一种由Intel开发用于并行编程的C++线程库,它不需要线程编程,允许运行时库自动地将逻辑并行映射到线程中,有效地利用了CPU资源,而且可以与其他线程兼容,实现无缝共存。

Java.util.concurrent:

一种Java语言用于并行编程的实用工具类,它包括了几个已经标准化的可扩展框架和一些提供有用功能的类。

2 结束语

多核多线程已成为处理器发展的一个大方向,它能提升计算机的性能,但面临着多核系统编程和程序正确性上的两个方面难题,隐式多线程可以有效地解决与缓解这两方面问题。

虽然隐式多线程实现技术很多,但其核心思想是控制系统中线程的数量,利用已有线程执行任务、创建线程数量要与计算机处理核心相匹配以及动态地调用线程数量。

猜你喜欢

编译器线程队列
实时操作系统mbedOS 互斥量调度机制剖析
面向理想性能空间的跨架构编译分析方法
队列队形体育教案
队列里的小秘密
基于多队列切换的SDN拥塞控制*
基于国产化环境的线程池模型研究与实现
运行速度大突破华为《方舟编译器》详解
在队列里
计算机中的多线程问题
优化编译器的设计