GCD --换种简单的方式理解

在开发的过程中,对于多线程的需求越来越高,但是由于在概念的理解上一直都有些许的模糊不清,所以这次也趁着重读一遍高级编程中的GCD部分,将多线程重新整理了一下。


1. 多线程的理解
2. GCD方法的理解

1. 多线程的理解

多线程的本义很好理解:就是为了多个不同的任务开启多个线程,让主线程能及时的响应用户的操作。但是对于和多线程紧紧相关的异步、同步和并行、串行而言,很容易搞模糊。所以下面还是按照自己的思路一步步进行分析:

1)队列

官方点的理解:队列就是任务的集合,采用的是先进先出的原则,每执行完一个任务就会释放一个任务。通白点理解就是:对于每一个新任务而言,先排到队伍的末尾,具体该如何执行等按序轮到才知道。

2)同步与异步

① 同步:在当前线程中执行任务,并没有开启新线程的能力
② 异步:具有开启新线程的能力,能在新的线程中执行任务

首先,通过图例解释异步执行的过程:


异步执行示范

异步执行并不会堵塞当前的线程,只是告诉当前的线程:

你只要帮我将任务加入queue队列中即可,任务该如何执行无你无关。

所以从上面图例中的主线程视角看整个的执行过程,就是:


异步执行时主线程视角

主线程并不会直接看到block中关于任务的内容,只是将dispatch_async和NSLog都当做一行执行命令来执行。也就是说:主线程只管执行各个命令行,而队列中加入的任务在其他线程中执行:


异步执行打印结果

同步执行正好和异步执行相反,以下面的图例分析:


同步执行示范
不仅需要将任务加入到queue队列中,还会强制要求当前线程暂停,来执行该队列中的任务。

所以结果和执行的顺序一致:


同步执行的打印结果
3)队列类型:串行和并行

① 串行 --->一个任务执行完再执行下一个任务,按序一个个执行。

dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

① 并行 --->不等待当前任务执行完就执行下一个任务。

dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

同步还是异步、串行还是并行对于任务而言就相当于两个同等重要的原则。用商店的收银台为例来理解:

一家商店的收银处,同步表示只有一个收银台,而异步表示有多个收银台。而串行表示管你有几个
收银台,所有人就排成一队;而并行表示尽量分散,有几个排几个。

在对多线程的处理过程中,同步执行其实是很容易出错的地方。个人理解就是:在当前线程正在处理“将任务加入queue队列”中时,同步执行会强制性的要求当前线程暂停手中的任务,从而用所有的资源来执行"queue队列中的任务"。举例而言:


同步执行易报错点

主线程正在执行任务时,强制要求执行block中的新任务。


同步执行易报错点

异步执行创建的线程正在执行任务,强制要求执行同步中的任务。

所以在对同步执行的使用中,要特别注意不要进入到崩溃的逻辑中。

2. GCD方法的理解
dispatch_after
dispatch_after示例

对于该方法而言,有两个地方需要特别注意:
① NSEC_PER_SEC
dispatch_afer方法中的第二个参数的时间单位并不是秒而是"纳秒",所以这也是为什么需要使用系统定义的变量进行转换的原因。系统提供的装换方式:

每秒有多少纳秒
#define NSEC_PER_SEC 1000000000ull 
每微妙有过少毫秒
#define NSEC_PER_MSEC 1000000ull
每秒有多少毫秒
#define USEC_PER_SEC 1000000ull
每毫秒有多少纳秒
#define NSEC_PER_USEC 1000ull

②4秒之后执行?
dispatch_after并不是在指定时间后执行处理,而只是在指定时间内将任务追加到Queue队列中。
对于上面的图例而言,该队列是在主线程的RunLoop中执行,而主线程的RunLoop每隔1/60秒执行,而该Block中的任务要求延迟4秒之后执行,所以最快在4秒 +1/60后执行。并且由于主队列中有大量的处理或主线程本身就有一定的延迟,所以执行的时间会更长。

所以,dispatch_afer只适用于一些想大致延迟执行的处理中,并不适用于对时间有严格要求的情况下。
dispatch_barrier_async

对于多线程而言,最需要关注的就是数据竞争的问题。虽然串行执行能避免该问题,但是现实生活中数据的读取往往是要求能并行执行的,只有当遇到对数据的写入时才需要额外的关注。
举例而言:


并行执行读取和写入操作

很显然,读取和写入并行的情况下,读取的数据会出现错误:


简单的并行执行数据读取出错

而dispatch_barrier_async的定义就是:
等待之前的并行执行全部结束之后,再将指定的处理追加到队列中。等待该函数追加的处理执行完毕之后,队列才会恢复到一般的动作:


执行结果
所以,dispatch_barrier_async就是等待之前的并行操作执行之后,再单独的执行该函数中的任务处理,完毕之后就是普通的执行。
Dispatch Semaphore

在实际的开发过程中,经常会出现一种需求:在同一个界面中需要多次请求,在所有请求结束之后再刷新界面。在此之前,我一直都很low的用在一个请求结束时嵌入另一个请求的方法,直到认识到该方法:


信号量的使用

上面的图例有几个需要知道的地方:
①dispatch_semaphore_t
Dispatch Semaphore是持有计数的信号,计数为0时等待,计数为1或大于1时,减去1而继续执行。

首先,创建信号时赋值计数的初始值为0

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

其次,当信号量遇到wait方法时,判断计数是否大于等于1。如果等于0,进入等待状态,所以等价于该线程暂停在该处。所以:

[task resume]必须写在wait方法之前

最后,当任务执行结束,signal函数会将计数值加1,此时wait函数会识别到计数不为0,会减1继续向下执行。

dispatch_semaphore_signal(semaphore);

信号量配合group使用,当所有的请求结束时,通知主线程进行界面的刷新:


通知主线程进行界面刷新

对于类似多个网络请求的情况,GCD还提供了另外的一种方法:


多个网络请求第二种方法
dispatch_group_enter(group);
dispatch_group_leave(group);

关于越底层的东西,越值得深入的思考。GCD的理解也算是基本的入门,也想要更多的去了解这些东西。冬天到了,得好好学习了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容