多线程(二)方案
00 分钟
2020-8-27
2020-8-27
type
status
date
slug
summary
tags
category
icon
password
在上一篇文章中,了解进程及线程的基础知识,我们在本文探讨在iOS开发中所遇到的多线程方案,以及方案中涉及的相关概念。

一、多线程的方案

notion image
以上方案,除去pthread跨平台的方案,其他基于Objective-C苹果独有的方案,我们将在后面系列的文章中逐一阐述。

二、队列与同步异步

2.1 队列

在说明队列之前,先对几个概念再次重温:
  1. 线程用于指代独立执行的代码段,在 iOS 中,线程的底层实现是基于 POSIX threads API 的,也就是我们常说的 pthreads
  1. 进程(process)用于指代一个正在运行的可执行程序,它可以包含多个线程。
  1. 任务(task)用于指代抽象的概念,表示需要执行工作,可以理解为就是一段代码。
队列是一种先进先出(FIFO)线性的数据结构,是计算机系统为了对任务进行调度的一种抽象化机制——在线程 与任务之间搭建起桥梁,即将任务调度分配到具体的线程上。
一个队列由一个或多个任务组成,当这些任务要开始执行时,系统会分别把他们分配到某个线程上去执行。当有多个系统核心时,为了高效运行,这些核心会将多个线程分配到各核心上去执行任务,对于系统核心来说并没有任务的概念。
notion image
至于队列是串行还是并发,区别在于队列执行任务的方式——是否等待当前任务结束。
串行队列
并发队列
是否等待当前任务结束
表现
只能一个接着一个执行任务
可以并发执行任务
线程
每次对应一个线程,这个线程可能不变,也可能被更换
可能对应多个线程,也可能对应一个线程
注意上面两个关键词:只能可以
只能表示串行队列,一定是任务一个一个接着执行,不可能并发。
可以表示任务可以并发执行,但并不一定是并发执行的。因为,还需要看任务是否是同步还是异步提交的。
串行队列
notion image
并发队列
notion image

2.2 同步与异步

同步和异步操作的主要区别在于是否等待当前任务完成,亦即是否阻塞当前线程。
同步
异步
是否等待当前操作结束
表现
阻塞线程,执行完成才继续之后后续代码
不会阻塞线程,调用后立即返回
针对上面的术语,在iOS中:
notion image

三、各种队列的同步异步

下面我们针对各种队列的同步异步,进行代码演练,并进行总结,如下:
notion image
需要注意的是:在执行同步任务的过程中,系统会进行优化,一般来说,会将同步操作加入到当前正在运行的线程中去。

3.1 GCD

其中以GCD的方式来进行。
notion image
notion image

3.2 主队列

iOS 主队列本质是一个串行队列。

3.2.1 主队列同步

主队列-同步:崩溃
  1. 依次将任务提交到主队列:syncOperationMainThread、任务1;
  1. 在主线程先执行syncOperationMainThread,其内部需要执行任务1;
  1. 但执行任务1,根据串行队列的特点,又需要执行完syncOperationMainThread;
  1. 相互依赖对方执行完才能继续执行,产生死锁,崩溃。

3.2.2 主队列异步

主队列-异步
  1. 依次提交任务到主队列,所以是asyncOperationsOnMainThread,任务1;
  1. 主队列在主线程执行,执行asyncOperationMainThread,其中遇到任务1;
  1. 由于任务1是异步提交的,所以不需要等待任务1返回,可以继续asyncOperationMainThread;
  1. 执行完asyncOperationMainThread,继续在主线程执行异步提交的任务1。

3.3 串行队列

3.3.1 串行队列同步

串行队列-同步
  1. 主线程执行syncOperationsOnSerialThread;
  1. 将任务1同步提交到一个串行队列"serial",队列"serial",由于同步 任务不会创建新线程,所以在主线程执行任务1,由于是同步,需要等待执行完;
  1. 任务1执行完,回到主线程继续执行syncOperationsOnSerialThread。

3.3.2 串行队列异步

串行队列-异步
  1. 主线程执行asyncOperationsOnSerialThread;
  1. 将任务1异步提交到串行队列,队列将分配新线程执行任务1,由于是异步提交,无须立即返回结果和等待。回到主线程继续执行asyncOperationsOnSerialThread;
  1. 执行完asyncOperationsOnSerialThread,新线程依次执行任务1;

3.4 全局队列

全局队列本质上是一个并发队列。

3.4.1 全局队列同步

全局队列-同步
1.在主线程执行syncOperationsOnGloabThread;
2.将任务1提交到全局队列,遇到任务1,由于是同步提交,需要立即执行任务1,阻塞当前主线程;
2.1 原本任务1提交全局队列,是个并发队列,也就是任务1原本可以在多个线程并发执行,但由于同步需要单个任务串行执行;
2.2 而且由于同步操作的优化,原本任务1会在主线程之外的新进程串行进行,此处也会优化成在主线程执行;
3.待任务1执行完之后,继续执行syncOperationsOnGloabThread;

3.4.2 全局队列异步

全局队列-异步
1.在主线程执行asyncOperationsOnGloabThread;
2.将任务1提交到全局队列,并且以异步方式提交;
3.异步提交后,继续执行asyncOperationsOnGloabThread;
4.之后开始执行任务1,并且全局队列会调度多个新线程并发执行任务1。

3.5 并发队列

3.5.1 并发队列同步

并发队列-同步
  1. 执行syncOperationsOnConcurrentThread;
  1. 同步提交任务1到并发队列,由于是同步,将会等待任务1执行完毕;
  1. 并且由于优化,将同步任务分配到主线程执行;
  1. 执行完任务1后,继续执行syncOperationsOnConcurrentThread。

3.5.2 并发队列异步

并发队列-异步
  1. 执行asyncOperationsOnConcurrentThread
  1. 异步提交任务1到并发队列,由于异步提交,将会继续执行asyncOperationsOnConcurrentThread;
  1. 执行完后,并发队列将任务1分配到多个线程执行任务1

参考

链接

  1. 《深入解析Mac OS X & iOS 操作系统》
  1. Threading Programming Guide

示例代码

  1. 各种队列与同步异步