关于iOS 多线程开发——GCD的理解与使用


GCD是Grand Central Dispatch的缩写,有人叫它大中枢派发、或者大中央调度,不管叫啥,总之,它是iOS开发的一个多线程编程解决方法,比起NSThread、NSOperationQueue、NSInvocationOperation等多线程技术方案,使用起来更加简单方便。

GCD的优点:1.GCD是苹果公司为多核的并行运算提出的解决方案

                   2.GCD会自动利用更多的CPU内核(比如双核、四核)

                   3.GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

                  4.程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

一、基本概念理解

1、进程和线程的理解

1. 进程:正在进行中的程序被称为进程,负责程序运行的内存分配,每一个进程都有自己独立的虚拟内存空间。

2. 线程是进程中一个独立的执行路径,即主线程,主线程有1M的栈区,对于耗时的执行路径,可以放在子线程(512K栈区)中执行。

注意:(1)新建线程会消耗内存空间和CPU事件,线程太多会降低系统的运行性能,多线程是通过CPU时分复用实现的。

         (2)多线程是为了并发执行多项任务,不会提高单个算法本身的执行效率。

2、并发(Concurrency),并行(Parallelism)的理解

举个形象的例子:A、B两个基佬某天相约去小树林-------挖坑,

1. A和B各要挖一个坑,他们只有一把铁锨,于是两人商量,A挖一下,把铁锨给B,B挖一下,再把铁锨给A,这样交替使用铁锨,最后两人各挖了一个大坑,却总共花了20分钟。这就是并发;

2. A和B各要挖一个坑,他们各有一把铁锨,同时挖坑,最后,每个人各花了大概10分钟时间挖完了大坑。这就是并行。

由此可见,并发与并行的区别:并行是严格意义上的同时执行,而并发并不是严格的同时执行,而是以时间片为单位交替执行,所以不需要多处理器。

3、同步(sync)、异步(async)的理解

举个形象的例子:A、B是一对情侣,某天某时A男为B女做好了饭,于是喊B女去吃饭

1. B女在看韩剧,A一直喊她去吃饭,可是B一直不去,没办法,A只能等到B女看完韩剧才能一起吃饭,真爱需要等待,真爱就是同步

2. B女在看韩剧,A喊了一声后,没管来不来,自己就去吃饭了,这就是异步

区别:等待与不等待

4、GCD中串行队列(Serial Dispatch Queue) 、并发队列(Concurrent Dispatch Queue)的理解

GCD使用了队列的概念,解决了NSThread难于管理的问题,可以把队列想象成数组,通常我们把要执行的任务放到队列中管理

不管是串行队列(SerialQueue)还是并发队列(ConcurrencyQueue),都是FIFO队列。也就意味着,任务一定是一个一个地,按照先进先出的顺序来执行。

1.串行队列:在创建队列时,传参数DISPATCH_QUEUE_SERIAL表示创建串行队列。任务会一个一个地执行,只有前一个任务执行完成,才会继续执行下一个任务。 串行执行并不是同步执行的意思,一定要注意区分

2.并发队列:在创建队列时,传参数DISPATCH_QUEUE_CONCURRENT表示创建并发队列。并发队列会尽可能多地创建线程去执行任务。并发队列中的任务会按入队的顺序执行任务,但是哪个任务先完成是不确定的。

Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。

Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。

二、GCD的使用

创建队列的方法

dispatch_queue_t q = dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)

参数:

const char *label:队列的名称

dispatch_queue_attr_t attr:队列的属性,属性有两个,分别为:

DISPATCH_QUEUE_SERIAL(NULL)  串行队列

DISPATCH_QUEUE_CONCURRENT    并发队列

队列属性为宏,其中串行队列的宏值为NULL,所以创建一个串行队列可以用如下代码

dispatch_queue_t q = dispatch_queue_create(“jianshu", NULL);

同步和异步代表会不会开辟新的线程。串行和并发代表任务执行的方式。

同步串行和同步并发,任务执行的方式是一样的。没有区别,因为没有开辟新的线程,所有的任务都是在一条线程里面执行。

异步串行和异步并发,任务执行的方式是有区别的,异步串行会开辟一条新的线程,队列中所有任务按照添加的顺序一个一个执行,异步并发会开辟多条线程,至于具体开辟多少条线程,是由系统决定的,但是所有的任务好像就是同时执行的一样。

1.串行队列异步任务

因为是异步:(1)会创建新的线程(2)主线程执行时间不确定 

因为是串行队列:队列中所有任务按照添加的顺序一个一个执行

异步串行只会开辟一条新的线程去执行

2.并发队列异步任务

并行队列下地异步函数会开启N条子线程,且执行任务的顺序我们无法控制,至于是哪条线程执行任务由队列决定,哪个任务先完成由CPU决定。

结果中子线程4,5执行了多次任务,那是因为这两条线程执行完任务就会被线程池回收,队列再从线程池中去线程执行任务,这时就会线程重复利用,如果没有线程则会重新创建。

3.串行队列同步任务

同步任务不会开辟新线程,所以所有的的任务都会在主线程上依次执行


4.并发队列同步任务

同步任务不会开辟新线程,所以所有的的任务都会在主线程上依次执行

5.主队列

在应用启动的时候,就会自动创建与主线程关联的串行队列,我们也可能获取,不能手动创建。主队列专门负责调度主线程度的任务,没有办法开辟新的线程。所以,在主队列下的任务不管是异步任务还是同步任务都不会开辟线程,任务只会在主线程顺序执行。

(1)主队列异步任务:现将任务放在主队列中,但是不是马上执行,等到主队列中的其它所有任务除我们使用代码添加到主队列的任务的任务都执行完毕之后才会执行我们使用代码添加的任务。

(2)主队列同步任务:容易阻塞主线程,所以不要这样写。原因:我们自己代码任务需要马上执行,但是主线程正在执行代码任务的方法体,因此代码任务就必须等待,而主线程又在等待代码任务的完成好去完成下面的任务,因此就形成了相互等待。整个主线程就被阻塞了。

提示:注意主线程是一直工作的,除非将程序杀掉,否则主线程的工作永远不会结束。

6.全局队列

是一种特殊的并行队列,获取全局队列的方法:dispatch_get_global_queue(long identifier,unsigned long flags)

参数1:代表该任务的优先级,默认写0就行,不要使用系统提供的枚举类型(见过好多人都使用DISPATCH_QUEUE_PRIORITY_DEFAULT),因为ios7和ios8的枚举数值不一样,使用数字可以通用。

#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

参数2:苹果保留关键字,一般也写0

全局队列和并发队列的区别:

(1)全局队列没有名字,但是并发队列有名字。有名字可以便于查看系统日志

(2)全局队列是所有应用程序共享的。

(3)在mrc的时候,全局队列不用手动释放,但是并发队列需要。

全局队列的使用:通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:

7.dispatch_group_async的使用

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如执行四个下载任务,当四个任务都下载完成后才通知界面说完成。

关于dispatch_group_async其他使用的方式此处暂不考虑

8.dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

如果使用dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);会发现运行结果为:

说明dispatch_barrier_async的顺序执行还是依赖queue的类型啊,必需要queue的类型为dispatch_queue_create创建的,而且attr参数值必需是DISPATCH_QUEUE_CONCURRENT类型,前面两个非dispatch_barrier_async的类型的执行是依赖其本身的执行时间的,如果attr如果是DISPATCH_QUEUE_SERIAL时,那就完全是符合Serial queue的FIFO特征了。



9.dispatch_once

dispatch_once这个函数,它可以保证整个应用程序生命周期中某段代码只被执行一次!

10.dispatch_after

有时候需要等几秒钟后处理一些事情


注:动手练练有助于理解

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

推荐阅读更多精彩内容