gcd788788这个谁有微信号给我一个啊是谁的

百度拇指医生
&&&普通咨询
您的网络环境存在异常,
请输入验证码
验证码输入错误,请重新输入GCD其实没那么深奥
文/仁伯安(授权)
原文链接:/p/dbc7f4e4b24d
网上很多关于GCD的文章,其中不乏面面俱到,丝丝入扣的,但总觉更多的像是Apple的API的译文篇。殊不知“具体全面”,对于想快速掌握GCD框架的同志那就是个坑。鄙人觉得,要掌握GCD只需掌握两点概念,一是:任务;二是:队列,贯彻始终即可。
1. GCD简介
Grand Central Dispatch (GCD) 是Apple提供的多线程编程的解决方案之一(除此之外还有NSThread、NSOperation等)。
为什么要用GCD呢?
简单方便、简单方便、简单方便,重要的事情说三遍。使用GCD时,我们只需使用告诉系统要执行什么任务,而不需要编写任何线程管理代码,比如创建线程、任务调度、线程销毁等,我们都不必关心,GCD具有自动管理线程的生命周期的能力。
2. 任务和队列
下面我们重点说下GCD的两个核心:任务和队列。任务:
任务就是执行操作的意思,就是你在线程中要执行的那段功能代码,具体表现在代码中就是GCD的block中的语句块。任务执行有两种方式:同步任务和异步任务。两者的主要区别是:是否具备开启新线程的能力。
同步任务(sync):在当前线程中执行任务,阻塞当前线程至任务执行完毕,不具备开启新线程的能力
异步任务(async):可以在新的线程中执行任务,不会阻塞当前线程,而是开启新线程
队列指任务队列,即用来存放任务的队列。在GCD中有两种形式的队列:串行队列和并发队列。
并发队列(Concurrent Dispatch Queue):可以让多个任务并发(逻辑上同时)执行(自动开启多个线程同时执行对应任务),并发功能只有在异步(dispatch_async)函数下才有意义。
串行队列(Serial Dispatch Queue):任务一个一个地依次执行(顺序执行)
3. GCD的使用步骤
GCD的使用步骤相对简单,一般两步:
创建一个队列(串行队列或并发队列)
将任务添加到队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)
下边来看看队列的创建方法和任务的创建方法。
(1)队列的创建方法
可以使用dispatch_queue_create来创建队列,需要传入两个参数,第一个参数表示队列的唯一标识符,用于调试DEBUG,可为空;第二个参数用来识别是串行队列还是并发队列,DISPATCH_QUEUE_SERIAL表示串行队列,DISPATCH_QUEUE_CONCURRENT表示并发队列。
// 串行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create(&test.queue&, DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue= dispatch_queue_create(&test.queue&, DISPATCH_QUEUE_CONCURRENT);
对于Main queue,它本身是串行队列,通过dispatch_get_main_queue可以获取,一般和UI相关的任务,比如:更新UI界面的显示,下载完一张图片,在UI界面上进行更新。对于并发队列,还可以使用 dispatch_get_global_queue 来创建全局并发队列。GCD默认提供了全局的并发队列,需要传入两个参数。第一个参数表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT,第二个参数暂时没用,用0即可。 dispatch_get_global_queue 由整个进程共享。一般是后台长时间执行的任务,耗时操作(比如解析数据,下载文件等)。
(2)任务的创建方法
// 同步执行任务创建方法
dispatch_sync(queue, ^{
& &NSLog(@&%@&,[NSThread currentThread]); & &// 这里放任务代码
// 异步执行任务创建方法
dispatch_async(queue, ^{
& &NSLog(@&%@&,[NSThread currentThread]); & &// 这里放任务代码
既然我们有两种队列,两种任务执行方式,那么我们就有了四种不同的组合方式。这四种不同的组合方式是:
并发队列 + 同步执行
并发队列 + 异步执行
串行队列 + 同步执行
串行队列 + 异步执行
实际上,我们还有一种特殊队列是主队列,那样就有8种不同的组合方式了。
主队列 + 同步执行
主队列 + 异步执行
全局队列 + 同步执行(全局和并发一样不做区分)
全局队列 + 异步执行(全局和并发一样不做区分)
下边我们来分别讲讲这几种不同的组合方式的使用方法。
4. GCD的基本使用
先来讲讲并发队列的两种使用方法。
(1) 并发队列 + 同步执行
不会开启新线程,任务依次执行:
- (void)loadGCD
& &// 并发队列
& &dispatch_queue_t queue = dispatch_queue_create(&test.queue&, DISPATCH_QUEUE_CONCURRENT);
& &NSLog(@&syncConcurrent---begin&);
& &// 同步任务
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1------%@&, [NSThread currentThread]);
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2------%@&, [NSThread currentThread]);
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3------%@&, [NSThread currentThread]);
& &NSLog(@&syncConcurrent---end&);
输出结果:
15:11:29.606 GCDDemo[] syncConcurrent---begin
15:11:29.607 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:11:29.607 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:11:29.607 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:11:29.608 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:11:29.608 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:11:29.608 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:11:29.608 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:11:29.609 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:11:29.609 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:11:29.609 GCDDemo[] syncConcurrent---end
从并发队列 + 同步执行中可以看到,所有任务都是在主线程中执行的。由于只有一个线程,所以任务只能一个一个执行。
同时我们还可以看到,所有任务都在打印的syncConcurrent—-begin和syncConcurrent—-end之间,这说明任务是添加到队列中马上执行的。
(2) 并发队列 + 异步执行
可同时开启多线程,任务交替执行
- (void)loadGCD
& &// currentQueue sync
& &dispatch_queue_t queue = dispatch_queue_create(&currentQueueSync&, DISPATCH_QUEUE_CONCURRENT);
// & &NSLog(@&asyncConcurrent---begin&);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1------%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2------%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3------%@&, [NSThread currentThread]);
// & &NSLog(@&asyncConcurrent---end&);
输出结果:
15:12:41.284 GCDDemo[] 1------&NSThread: 0x&{number = 3, name = (null)}
15:12:41.284 GCDDemo[] 2------&NSThread: 0x&{number = 4, name = (null)}
15:12:41.284 GCDDemo[] 3------&NSThread: 0x&{number = 5, name = (null)}
15:12:41.284 GCDDemo[] 1------&NSThread: 0x&{number = 3, name = (null)}
15:12:41.284 GCDDemo[] 2------&NSThread: 0x&{number = 4, name = (null)}
15:12:41.284 GCDDemo[] 3------&NSThread: 0x&{number = 5, name = (null)}
15:12:41.285 GCDDemo[] 1------&NSThread: 0x&{number = 3, name = (null)}
15:12:41.285 GCDDemo[] 2------&NSThread: 0x&{number = 4, name = (null)}
15:12:41.285 GCDDemo[] 3------&NSThread: 0x&{number = 5, name = (null)}
在并发队列 + 异步执行中可以看出,程序开启了3个线程,并且任务是交替着同时执行的。
(3) 串行队列 + 同步执行
不开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个:
- (void)loadGCD
& &NSLog(@&syncSerial---begin&);
& &dispatch_queue_t queue = dispatch_queue_create(&serialQueuesync&, DISPATCH_QUEUE_SERIAL);
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1------%@&, [NSThread currentThread]);
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2------%@&, [NSThread currentThread]);
& &dispatch_sync(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3------%@&, [NSThread currentThread]);
& &NSLog(@&syncSerial---end&);
输出结果为:
15:13:26.201 GCDDemo[] syncSerial---begin
15:13:26.201 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:13:26.201 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:13:26.202 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:13:26.202 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:13:26.202 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:13:26.202 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:13:26.203 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:13:26.203 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:13:26.203 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:13:26.203 GCDDemo[] syncSerial---end
在串行队列 + 同步执行可以看到,所有任务都是在主线程中执行的,并没有开启新的线程。而且是顺序一个个执行。
(4) 串行队列 + 异步执行
会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个:
- (void)loadGCD
& &// serial queue async
& &dispatch_queue_t queue = dispatch_queue_create(&serialQueueasync&, DISPATCH_QUEUE_SERIAL);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3----%@&, [NSThread currentThread]);
输出结果为:
15:14:07.906 GCDDemo[] 1----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.907 GCDDemo[] 1----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.907 GCDDemo[] 1----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.908 GCDDemo[] 2----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.908 GCDDemo[] 2----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.909 GCDDemo[] 2----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.909 GCDDemo[] 3----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.909 GCDDemo[] 3----&NSThread: 0x&{number = 6, name = (null)}
15:14:07.909 GCDDemo[] 3----&NSThread: 0x&{number = 6, name = (null)}
在串行队列 + 异步执行可以看到,开启了一条新线程,但是任务还是串行,所以任务是一个一个执行。
主队列:系统提供的一种特殊的串行队列,所有放在主队列中的任务,都会放到主线程中执行,可使用dispatch_get_main_queue()获得主队列,一般和UI相关的任务,比如:更新UI界面的显示,下载完一张图片,在UI界面上进行更新:
我们再来看看主队列的两种组合方式。
(5) 主队列 + 同步执行
线程死锁等待
- (void)loadGCD
& &dispatch_queue_t mainQueue = dispatch_get_main_queue();
& &dispatch_sync(mainQueue, ^{ // A
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1------%@&, [NSThread currentThread]);
& &dispatch_sync(mainQueue, ^{ // B
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2------%@&, [NSThread currentThread]);
& &dispatch_sync(mainQueue, ^{ // C
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3------%@&, [NSThread currentThread]);
这时候,我们惊奇的发现,在主线程中使用主队列 + 同步执行,会造成线程死锁。
这是因为同步执行有个特点,就是对于任务是立马执行的。那么当我们把第一个任务A放进主队列中,它就会立马执行。但是主线程现在正在处理其他方法,所以任务A需要等其他方法执行完才能执行。而其他方法执行到任务A的时候,又要等任务A执行完才能往下执行B和任务C,这是就会相互等待,造成死锁。
(6) 主队列 + 异步执行
只在主线程中执行任务,执行完一个任务,再执行下一个任务
- (void)loadGCD
& &dispatch_queue_t mainQueue = dispatch_get_main_queue();
& &dispatch_async(mainQueue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&1------%@&, [NSThread currentThread]);
& &dispatch_async(mainQueue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&2------%@&, [NSThread currentThread]);
& &dispatch_async(mainQueue, ^{
& & & &for (int i = 0; i & 3; ++i)
& & & & & &NSLog(@&3------%@&, [NSThread currentThread]);
输出结果:
15:15:52.362 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:15:52.363 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:15:52.363 GCDDemo[] 1------&NSThread: 0x&{number = 1, name = main}
15:15:52.364 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:15:52.364 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:15:52.364 GCDDemo[] 2------&NSThread: 0x&{number = 1, name = main}
15:15:52.364 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:15:52.364 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
15:15:52.365 GCDDemo[] 3------&NSThread: 0x&{number = 1, name = main}
我们发现所有任务都在主线程中,虽然是异步执行,具备开启线程的能力,但因为是主队列,所以所有任务都在主线程中,并且一个接一个执行。
GCD线程之间的通讯
在iOS开发过程中,我们只能在主线程里边进行UI刷新。我们通常把一些耗时的操作放在其他线程,比如说文件下载等耗时操作。更多的时候,我们需要在处理完耗时操作后,回到主线程去处理UI更新任务,那么就用到了线程之间的通讯。
- (void)loadCommGCD
& &dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
& & & &for (int i = 0; i & 10; ++i) { // 耗时任务
& & & & & &NSLog(@&1------%@&,[NSThread currentThread]);
& & & &// 回到主线程
& & & &dispatch_async(dispatch_get_main_queue(), ^{
& & & & & &NSLog(@&2-------%@&,[NSThread currentThread]);
& & & &});
15:20:04.020 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.020 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.020 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.021 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.021 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.021 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.021 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.022 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.022 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.022 GCDDemo[] 1------&NSThread: 0x&{number = 10, name = (null)}
15:20:04.026 GCDDemo[] 2-------&NSThread: 0x&{number = 1, name = main}
可以看到在其他线程中先执行操作,执行完了之后回到主线程执行主线程的相应操作。
6. GCD的其他方法
(1) GCD的栅栏方法 dispatch_barrier_async
* 我们有时需要异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作。
* 这样我们就需要一个相当于栅栏一样的一个方法将两组异步执行的操作组给分割起来,
* 当然这里的操作组里可以包含一个或多个任务。
* 这就需要用到dispatch_barrier_async方法在两个操作组间形成栅栏。
- (void)loadGCD
& &// 并发队列,barrier_async
& &dispatch_queue_t queue = dispatch_queue_create(&barrier_async&, DISPATCH_QUEUE_CONCURRENT);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----1-----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----2-----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----0-----%@&, [NSThread currentThread]);
& &dispatch_barrier_async(queue, ^{
& & & &NSLog(@&----我是barrier,可以等待前面的线程并发执行完成后,之后并发执行栅栏后面的线程-----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----3-----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----4-----%@&, [NSThread currentThread]);
& &dispatch_async(queue, ^{
& & & &NSLog(@&----5-----%@&, [NSThread currentThread]);
输出结果:
15:17:52.049 GCDDemo[] ----1-----&NSThread: 0xc0&{number = 7, name = (null)}
15:17:52.049 GCDDemo[] ----2-----&NSThread: 0xddc0&{number = 8, name = (null)}
15:17:52.049 GCDDemo[] ----0-----&NSThread: 0x&{number = 9, name = (null)}
15:17:52.049 GCDDemo[] ----我是barrier,可以等待前面的线程并发执行完成后,之后并发执行栅栏后面的线程-----&NSThread: 0x&{number = 9, name = (null)}
15:17:52.049 GCDDemo[] ----3-----&NSThread: 0x&{number = 9, name = (null)}
15:17:52.049 GCDDemo[] ----4-----&NSThread: 0xddc0&{number = 8, name = (null)}
15:17:52.049 GCDDemo[] ----5-----&NSThread: 0xc0&{number = 7, name = (null)}
可以看出在执行完栅栏前面的操作之后,才执行栅栏操作,最后再执行栅栏后边的操作。
(2) GCD的延时执行方法 dispatch_after
当我们需要延迟执行一段代码时,就需要用到GCD的dispatch_after方法。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(&#delayInSeconds#& * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
& & & &&#code to be executed after a specified delay#&
(3) 单次执行 dispatch_once
我们在创建单例、或者有整个程序运行过程中只执行一次的代码时,我们就用到了GCD的dispatch_once方法。详细使用见:哥的单例是伪的还是真的有图为证(Singleton)
微信篇幅有限,请继续阅读:/p/dbc7f4e4b24d
一键分享到:
最近我们老大貌似也关注起了农药,昨天还在我们群里发了一个农药的统计表,来给你们瞅一眼。看见了没,这个游戏居然
“很久以前,我们曾有8000个外壳被盗,这些工厂女工把它们藏在内衣里。”
iOS开发 iOS开发 第一次见女朋友爸妈 给他们送的肾宝片 结果女友和我闹分手 哈哈哈哈 送什么不好 居然送肾宝片 图片来源:逗比啊 iOS开发整理发布,转载请联系作者授权 ↙点击“阅读原文”,加入
『程序员大咖』
前两天是一年一度的“618”电商节,剁手的小伙伴们在哪里,快举起你们的双手,让哎妹看一看!对于哎妹这种勤俭节
夏天到了,很多情况下 iPhone 的 Home 键延迟都会相对严重。可能是由于夏天出汗引起的,又或者是干燥
5月8日母亲节献礼华盛斯巴鲁团购惠其实我真的很怕!因为你说你喜欢雨,但你在下雨的时候却打着伞;你又说你喜欢太
安全驾驶,信心才能增长,规范操作,欢乐才能持续!
孩子成绩不理想?孩子学校里遇到挫折?家长们听了心里着急,老师也很着急!但是,家长光着急也没用,重要的是,要怎么和老师配合,怎么和老师沟通!家长与老师配合得越好,教育就越成功!
高考结束了!好好放松下,去哪里耍?道滘欢迎你!道滘美食节欢迎你!好吃的,好玩的,根本停不下来······还有直升机、无人机体验~~~
What?文成又上浙江卫视了!不是前两天刚上过么,又上?对啊!颜值高就是这么任性!小文有些激动了
最新iOS、iPhone资讯,万名iOS开发者、swift开发、果粉聚集,参与技术讨论,整理开发技巧,分享创业经验!享受生活、热爱编程!
感谢您的支持,请按照如下步骤取消屏蔽ABBAO的广告():

我要回帖

更多关于 谁有不用的微信号 的文章

 

随机推荐