加入收藏 | 设为首页 | 会员中心 | 我要投稿 济宁站长网 (https://www.0537zz.cn/)- 行业智能、边缘计算、专有云、AI硬件、5G!
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

多线程开发中线程数量设计问题

发布时间:2019-09-27 02:51:06 所属栏目:优化 来源:道以致远
导读:前言 前面我们用了几篇文章系统的说了一下有关Java并发编程模型中的一些基础的知识。比如同步,锁,原子性操作,信号量等以及它们的一些延展实现闩锁,栅锁等等。 今天我们回过头来简单说一下并发编程模型的设计和选择。 主要涉及到我们如何利用多线程设计
副标题[/!--empirenews.page--]

 前言

前面我们用了几篇文章系统的说了一下有关Java并发编程模型中的一些基础的知识。比如同步,锁,原子性操作,信号量等以及它们的一些延展实现闩锁,栅锁等等。

多线程开发中线程数量设计问题

今天我们回过头来简单说一下并发编程模型的设计和选择。

主要涉及到我们如何利用多线程设计来在多处理器或者多内核时代如何提高我们应该程序的性能。

说说线程和应用程序之间的关系,以及我们在编程过程中如何去设计多线程模型。是不是我们编程时设计的线程越多对应用程序的性能提升越大,什么情况下设计什么样的线程模型。

并发与并行

在具体说多线程并发模型设计之前,我们先来简单澄清两个概念,并发(Concurrency)和并行(Parallel),

它们是两个容易混淆的概念,它们的基础都是多线程,而并行是指多个进程或线程之间在运行时同一时间里并行的执行。

而并发则是多个线程一起共同去完成某一项任务。可以在单核处理器上分时运行实现,也可以在多核处理器上并行运行实现。

所以说并发偏重于是编程级别的概念,而并行则多指运行方式的概念。并行可以是进程级别上,多个进程同时运行,也可以是线程级别的多个独立线程的并行运行。强调的是同一时间上的同时发生。

我们通常所说的并发编程,实质就是通过多个线程来分解要执行的任务,使其成为多个可独立执行的小任务,做到可以在单核上分时执行,也可以在多核上并行执行。从而缩短总任务的处理时间,从而提高应用程序的性能。

多线程并发编程模型

在编程领域里,并发编程设计其实是跟顺序同步编程或者串行化编程设计相对的。

串行化编程是将任务排队,针对的运行它的目标处理器只有一个,而且数单线程处理的。要提高这类应用程序的性能,我们只能通过提高该该处理器的执行效率来完成,但是它的提升是有限的,毕竟单核的处理能力是有上限的。

当我们的计算机进入多内核时代后,串行化编程所使用的单线程模型是无法使用多内核的,为此我们将应用程序的执行任务分解成可独立执行的小任务,交给多个线程,让它们在多个内核上并行执行。

多个处理器或者内核并行的执行多个线程,能够很好发挥并发编程模型的威力,缩短应用代码的执行时间。

这就是为什么我们进入多处理器或者多内核计算机时代后,多线程编程成为提高应用程序的性能的一个重要的选项。

因为这种设计能够给我们带来极大的应用程序性能提高,同时还能增强我们应用程序的响应性。

当然,在单核时代并发编程模型也能够在一定程度上提高应用程序效率,因为并发编程模型会将一个大的任务分解成由多个线程负责的众多小任务,在一个单核处理器上借助处理器的分时处理机制来执行,从而有效的利用了任务执行过程中出现的等待时间。

多线程应用程序分类

正是由于进入多核时代后,每个可用CPU内核都可以独立处理自己的任务,真正在运行时做到了并行,所以在并发编程模型中,我们将一个大任务分解为一系列独立运行的小任务,交给多个CPU内核来并行执行,从而真正的大大提高了整个应用程序的总运行效率。

一般情况下,我们在设计多线程并发编程模型时会首先考虑将我们的应用程序进行一个简单的分类,就是去识别是计算密集型程序还是I/O密集型的应用程序。

因为这两种类型的程序在CPU上执行时有很大的不同,如果是计算密集型程序其处理主要集中在从寄存器读取数据进行运算然后写入寄存器这样的过程,由于寄存器缓存的读写速度更靠近于CPU内部缓存,所以CPU的计算时间可以很好的被利用,不需要进行等待和上下文的切换。

而对于IO密集型应用程序来说,由于涉及到大量的输入/输出操作而这些大多是由专门的输入输出设备来负责处理的,由于它们的处理速度跟CPU有太大的差距,造成了CPU过多的等待时间的浪费。

为了能够充分利用现在多处理器或多内核的计算机算力,我们采用多线程并发设计编程来提高应用程序的性能是必由之路。下面我们举例说明上面两种类型应用的设计:

计算密集型应用程序多线程设计

首先看计算密集型应用,这种类型的处理,最常见的例子比如我们想处理硬盘上某个文件夹里的图片大小的应用,由于我们可以一次性将相关数据读入处理的内存,接下来重要的就是对数据进行运算处理了,属于计算密集型处理。

如果是单线程方法来实现的话,单线程方法需要遍历所有文件并依次缩放每个图片。

这种单线程模型下,即使我们有一个具有多个核心的CPU,调整大小的过程将只使用一个可用的CPU内核。

而如果采用多线程方法可以定义一个主线程负责扫描文件系统并将所有找到的文件添加到一个队列中,该队列由一组工作线程来负责处理。

那么这时候就要注意了,这种情况下我们如何设计我们的多线程处理模型呢?

我们简单想一下就知道,计算过程最好是每个CPU绑定特定的线程,不断的读取数据处理即可。

所以如果我们刚好有与可用CPU内核数一样多的工作线程,那么我们就能确保每个可用的CPU内核在处理图片时都有事情可做。

充分利用计算机的算力,也不存在线程上下文切换问题,也不存在等待输入输出问题,从而缩短图片的处理时间,提供整个应用程序的性能。

也就是说在我们并发模型设计时,如果主要涉及到数据的运算问题,我们可以设计跟可以使用的CPU内核数相同的线程数,以绑定执行线程的CPU内核,来充分的利用空闲的CPU内核处理能力。

这种情况下,如果从可扩展性考虑,我们可能想通过添加更多资源来提高性能,那么只能通过提高单个CPU算力的角度来实现。

假如在这个例子中,我们遇到了更大量的图片需要处理,我们是否能够为我们的应用程序添加更多的线程来处理呢?

其实这种计算密集型应用,由于我们当前机器的CPU内核数量有限,添加更多的线程并不能提高性能。

反而由于负责调度的线程必须管理更多的工作线程,并且线程的创建和关闭也会消耗CPU,而会出现增加越多线程性能反而可能下降的现象。

I/O密集型的应用程序多线程设计

对于输入/输出密集型应用程序来说,也就是说就是具有大量I/O等待时间的应用程序,利用多线程提高应用程序整体性能,如何设计呢?

我们来假想一个例子,假设我们想要编写一个应用程序,将一个完整的网站内容以HTML文件的形式镜像到硬盘上。因为涉及到网络访问,需要大量的网络I/O操作。

所以,它是典型的输入/输出密集型应用。

(编辑:济宁站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读