iOS开发项目化经典教程
上QQ阅读APP看书,第一时间看更新

1.1 多线程概念

由于一条线程同一时间只能处理一个任务,所以一个线程里的任务必须顺序执行。如果遇到耗时操作(如网络通信、耗时运算、音乐播放等),等上一个操作完成再执行下一个任务,则在此时间内用户得不到任何响应,这是很糟糕的用户体验。因此在iOS编程中,通常将耗时操作单独放在一个线程里,而把与用户交互的操作放在主线程里,保证应用及时响应用户的操作,提高用户体验。接下来,将围绕多线程技术进行详细讲解。

1.1.1 多线程概述

多线程是指从软件或者硬件上实现多个线程并发执行的技术。多线程技术使得计算机能够在同一时间执行多个线程,从而提升其整体处理性能。

想要了解多线程,必须先理解进程和线程的概念。进程是指在系统中正在运行的应用程序。这个“运行中的程序”就是一个进程。每个进程拥有着自己的地址空间。

当一个程序进入内存运行时,就会变成一个进程,运行中的每个程序都对应着一个进程,且进程具有一定的独立功能。打开Mac的活动监测器,可以看到当前系统执行的进程,如图1-1所示。

0

图1-1 Mac系统当前的进程

由图1-1可知,该窗口第1列显示的是“进程名称”,该列的每个应用程序就是一个单独的进程。第4列显示的是当前进程拥有的线程数量,而且不止一条。

进程作为系统进行分配和调度的一个独立单位,它主要包含以下3个主要特征。

(1)独立性

进程是一个能够独立运行的基本单位,它既拥有自己独立的资源,又拥有着自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户的进程是不可以直接访问其他进程的地址空间的。

(2)动态性

进程的实质是程序在系统中的一次执行过程,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,它就具有自己的生命周期和各自不同的状态,进程是动态消亡的。

(3)并发性

多个进程可以在单个处理器中同时执行,而不会相互影响,并发就是同时进行的意思。

需要注意的是,CPU在某一个时间点只能执行一个程序,即只能运行一个单独的进程,CPU会不断地在这些进程之间轮换执行。假如Mac同时运行着QQ、music、PPT、film4个程序,它们在CPU中所对应的进程如图1-2所示。

图1-2展示了CPU在多个进程间切换执行的效果,由于CPU的执行速度相对人的感觉而言太快,造成了多个程序同时运行的假象。如果启动了足够多个程序,CPU就会在这么多个程序间切换,这时用户会明显感觉到程序的运行速度下降。

0

图1-2 CPU执行的进程

多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。一个程序的运行至少要有一个线程,一个进程要想执行任务,必须依靠至少一个线程,这个线程就被称作主线程。线程是进程的基本执行单元,对于大多数应用程序而言,通常只有一个主线程。

当进程被初始化之后,主线程就被创建了,主线程是其他线程最终的父线程,所有界面的显示操作必须在主线程进行。开发者可以创建多个子线程,每条线程之间是相互独立的。假如QQ进程中有3个线程,分别用来处理数据发送、数据显示、数据接收,则它们在进程中的关系如图1-3所示。

0

图1-3 进程与线程

由图1-3可知,一个进程必定有一个主线程,每个线程之间是独立运行的,因此,线程的执行是抢占式的,只有当前的线程被挂起,另一个线程才可以运行。

一个进程中包含若干个线程,这些线程可以利用进程所拥有的资源。通常都是把进程作为分配资源的基本单位,把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,因此对它进行调度所付出的开销就会小得多,能更高效地提高系统内多个程序间并发执行的程度。

当操作系统创建一个进程的时候,必须为进程分配独立的内存空间,并且分配大量的相关资源。但是创建一个线程则要简单得多,因此使用多线程实现并发要比使用多进程性能高很多。总体而言,使用多线程编程有以下优势。

(1)进程间不能共享内存,但是线程之间共享内存是非常容易的。

(2)当硬件处理器的数量有所增加时,程序运行的速度更快,无需做其他任何调整。

(3)充分发挥多核处理器的优势,将不同的任务分配给不同的处理器,真正进入“并行运算”的状态。

(4)将耗时、轮询或者并发需求高的任务分配到其他线程执行,而主线程则负责统一更新界面,这样使得应用程序更加流畅,用户的体验更好。

凡事有利必有弊,多线程既有着一定的优势,同样也有着一定的劣势。如何扬长避短,这是开发者需要注意的问题。多线程的劣势包括以下3方面。

(1)开启线程需要占用一定的内存空间(默认情况下,主线程最大占用1M的栈区空间,子线程最大占用512K的栈区空间),如果要开启大量的线程,势必会占用大量的内存空间,从而降低程序的性能。

(2)开启的线程越多,CPU在调度线程上的开销就会越大,一般最好不要同时开启超过5个线程。

(3)程序的设计会变得更加复杂,如线程之间的通信、多线程间的数据共享等。

1.1.2 线程的串行和并行

如果在一个进程中只有一个线程,而这个进程要执行多个任务,那么这个线程只能一个个地按顺序执行这些任务,也就是说,在同一个时间内,一个线程只能执行一个任务,这样的线程执行方式称为线程的串行。如果在一个进程内要下载文件A、文件B、文件C,则线程的串行执行顺序如图1-4所示。

图1-4中,一个进程中只存在一个线程,该线程需要执行3个任务,每个任务都是下载一个文件。按照先后添加的顺序,只有上一个文件下载完成之后,才会下载下一个文件。

0

图1-4 线程的串行

如果一个进程中包含的不止有一条线程,每条线程之间可以并行(同时)执行不同的任务,则称为线程的并行,也称多线程。如果在一个进程内要下载文件A、文件B、文件C,则线程的并行执行顺序如图1-5所示。

0

图1-5 线程的并行

图1-5中,一个进程拥有3个线程,每个线程执行1个任务,3个下载任务没有先后顺序,可以同时执行。

同一时间,CPU只能处理一个线程,也就是只有一个线程在工作。由于CPU快速地在多个线程之间调度,人眼无法感觉到,就造成了多线程并发执行的假象,多线程原理图如图1-6所示。

0

图1-6 多线程的原理

由图1-6可知,一个进程拥有3个线程,分别为线程A、线程B、线程C。某一时刻,CPU执行线程A为一个小箭头的时间,之后又切换到线程B、线程C,依次类推,这样就形成了多条线程并发执行的效果。

1.1.3 多线程技术种类

iOS提供了4种实现多线程的技术,这些技术各有侧重,既有着一定的优势,也存在着各自的不足,开发者可根据自己的实际情况选择。接下来,通过一张图来描述这4种技术方案,如图1-7所示。

0

图1-7 多线程技术方案

从图1-7中可以看出,pthread可以实现跨平台多个系统的开发,但是它通过C语言操作,使用难度很大,所以一般不被程序员采用。NSThread是面向对象操作的,通过OC语言来执行操作,但是操作步骤繁多,不易控制,也只是偶尔使用。但是,NSThread的内容有助于初学者理解多线程的本质和实现原理,后面会针对它进行详细的介绍。GCD充分利用了设备的多核优势,用于替代NSThread技术。NSOperation基于GCD,更加面向对象。GCD和NSOperation都是自动管理线程的,在实际开发中更受开发者推崇。后面的小节也会对GCD和NSOperation进行详细的介绍。