GCD多线程

Posted iOS笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GCD多线程相关的知识,希望对你有一定的参考价值。

GCD本质线程自动管理指令包


GCD优点:


1.GCD 本身自带有线程锁的效果,能通过推迟昂贵计算任务并在后台运行它们来改善应用的响应性能。


2.GCD 提供了更易于使用的并发模型(效果方面类似于对锁和线程进行封包,程序员使用的过程中本身可以不直接接触锁和线程)避开并发陷阱(锁和线程的相关陷阱)。


3.GCD 具有在常见模式(如单例,mvc)上采用更高性能的原语(封包后只需要考虑出入接口问题)优化代码的能力。


函数指令与相应的任务:


函数指令是一系列的代码指令的集合,可以为计算机平台识别的指令的集合。

计算机的相关平台在接收到函数指令之后,平台将会作出一系列的应对措施既执行一系列的应对操作行为(任务)。从本质方面而言,指令为因任务为果。


Serial vs. Concurrent 串行 vs. 并发


共同点:描述当前任务相对于其它任务被执行状态。(都强调任务)


差异:串行是逐个逐个,每次有且仅有一个任务被执行。并发是在同一时间可以有多个任务被执行。


Synchronous vs. Asynchronous 同步 vs. 异步


共同点:描述当前的函数指令相对于其相应任务(指令函数要求 GCD 执行的任务)的状态。同步函数可以视为异步函数的一种特殊情况。同步异步研究的内容是函数指令与其相应任务间的关系(同一个当前线程下的研究)。


差异:


同步:只在指令函数预定的任务已经完成后,计算机才返回指令函数入口(出口)处,进入下一个指令重复。同步条件下任务只能逐个执行,故同步必串行,同步并发无意义。


异步:无论预定的任务当前是否已经完成,计算机都会由当前立即返回指令函数入口(出口)处,进入下一个指令重复。也就是说预定的任务最终肯定会完成但计算机不会等着它完成而是立即返回指令函数入口(出口)处。异步函数(指令)不会阻塞当前线程去执行下一个函数(指令),同步函数(指令)会阻塞当前线程去执行下一个函数(指令)。


同步函数为当前线程下的阻塞函数。


Critical Section 临界区


同一段代码不能被多个线程并发执行,也就是,多个线程不能同时执行某段代码。因为代码去操作一个共享资源,例如一个共享变量资源若共享的变量资源被多个进程/线程并发访问,那么它很可能会变质(它的值不再可信)。


Race Condition 竞态条件


基于特定序列或时机的事件的软件系统以不受控制的方式运行的行为。如程序的并发任务执行的确切顺序即为一种静态条件。竞态条件可导致无法预测的行为,而不能通过代码检查立即发现。


Deadlock 死锁


第一个线程指令的执行以第二个线程指令的完成作为前提同时第二个线程指令的执行又以第一个线程指令的完成作为前提;两个线程指令互相等待着对方先完成,两个线程指令都处于互相等待的状态,结果导致彼此都未能够执行,两个线程指令处于相互卡死状态(死锁)。故死锁状态下程序不在执行下去。


Thread Safe 线程安全


具有线程安全性的代码能在多线程或并发任务中被安全的调用,而不会导致数据损坏,崩溃等问题。线程不安全的代码在某一个/同一个时刻只能在一个线程上下文中运行。 NSDictionary代码是线程安全代码,所以在同一时间在多个线程中使用它而不会有问题。NSMutableDictionary代码属于线程非安全代码,同一时刻只能有一个线程访问代码。


Context Switch (线程之间)上下文切换(额外的开销)


(线程之间)上下文切换指当你在单个进程里对不同的线程进行切换执行期间(由一个线程切换为另一个线程期间)存储与恢复执行状态的过程。


Concurrency vs Parallelism 单核并发与多核并行


单核cpu处理器下,并发代码的各个部分采用抢占cpu资源的方式在纳米级时间段内进行线程间并发代码的切换,此时线程间的并发代码是否发生或怎样的顺序发生无法确定。


对于多核cpu设备而言,多个线程上的代码以并行方式运行,既每一个线程都可以单独获取一个独立的cpu独立运行,不需要不断的相互切换线程。若为了使单核cpu设备也能实现并行,必须先运行一个线程,执行一个线程上下文切换,上下文切换之后再运行另一个线程或进程。


并行可以视为并发的特殊情况,并行要求并发,但并发并不能保证并行。并发为必要不充分的代码构造条件。


Queues 队列(FIFO)


GCD可用dispatch queues处理任务代码块block,调度队列管理着提供给GCD的代码块block任务并才用 FIFO队列顺序执行这些block任务。第一个被添加到队列里的任务会是队列中第一个开始的任务,而第二个被添加的任务将第二个开始,如此直到队列的终点。(调度队列本身属于一种管理代码(管理代码也是代码)且为线程安全代码可从多个线程并行的访问。)


Serial Queues 调度串行队列还是Concurrent Queues 调度并发队列都遵循FIFO先进先出先执行,后进后出后执行的原则,区别在于怎样的状态下的后执行。

调度串行队列中一次只能够执行一个任务,既后一个模块任务被执行的前提条件必须为前一个模块任务已经完成且前一个Block任务结束时间点和后一个模块任务开始时间点之间的过渡时间段长度不确定(受到 GCD 的控制)。调度串行队列中每一个模块任务的执行时机受到 GCD 的控制进而不可确定;唯一能确保的事情是 在调度串行队列GCD一次只执行一个任务,并且按照FIFO顺序来执行。


在GCD环境下,需要新增的子线程(数目)不需要程序员本身亲自生成而是由系统后台按需要自动生成并分配。由于GCD串行队列中同一时间只会执行一个模块任务也就只会生成一个子线程(一个子线程执行一个代码模块任务),不会出现同时访问临界区的风险;如果访问临界区的唯一方式是通过提交到调度串行队列的任务,那么不需要担心临界区的安全问题了。


Concurrent Queues 调度并发队列(纳米级误差有序执行)


并发队列中任务的开始执行是FIFO有序的而任务的完成顺序则是任意的;不会知道何时开始运行下一个任务,或者任意时刻有多少 Block 在运行。


何时开始一个 Block 完全取决于 GCD 。如果一个 Block 的执行时间与另一个重叠,也是由 GCD 来决定是否将其运行在另一个不同的核心上,如果那个核心可用,否则就用上下文切换的方式来执行不同的 Block 。


Queue Types 队列类型(2大类6小种)


1)并发队列(全局调度队列)(Global Dispatch Queues):background、low、default和high优先级。Apple的API也使用这些全局调度队列,所以这些队列中实际管理的任务既有应用代码指令任务也有平台支持指令包中支持指令任务。


2)串行队列:普通串行队列和特殊串行队列既主队列(每次/同一时刻只能够执行一个任务)。


注:主队列中所有的模块任务都只能由主线程执行,不存在危险临界区问题。同时,主线程是唯一可用于更新 UI的线程。主队列中的代码块一般为刷新ui指令,这个队列就是向UIView发生消息或发送通知。


3)6种队列:主队列,4个全局调度队列,自建队列


以上是关于GCD多线程的主要内容,如果未能解决你的问题,请参考以下文章

多线程——GCD

iOS多线程之GCD小记

iOS多线程开发之GCD(下篇)

多线程编程GCD

多线程GCD

iOS-多线程之GCD(原创)