iOS之浅谈GCD

GCD的基本思想


  • GCD的基本思想是将操作放在队列中去执行
    (1)操作使用block定义。
    (2)队列负责调度任务执行所在的线程以及具体的执行时间。
    (3)队列的特点是先进先出,新添加到队列的操作排在最后。
  • 队列 dispatch_queue_t
    (1) DISPATCH_QUEUE_SERIAL:串行队列,队列中的任务只会顺序执行。
    (2) DISPATCH_QUEUE_CONCURRENT:并行队列,队列中的任务通常会并发执行。
  • 操作
    dispatch_async 异步操作,会并发执行,不会顺序执行。
    dispatch_sync 同步操作,会依次顺序执行,能决定任务执行的顺序。

一、DISPATCH_QUEUE_SERIAL: 串行队列:
- (void) GCD
{

//DISPATCH_QUEUE_SERIAL串行队列,会死锁,但是会执行嵌套同步操作之前的代码
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue, ^{
    NSLog(@"读书===%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"吃饭====%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"上厕所====%@", [NSThread currentThread]);
}); 
}

2016-04-13 16:24:22.100 test[25089:1136445] 读书===<NSThread: 0x7fb050700ee0>{number = 2, name = (null)}
2016-04-13 16:24:22.101 test[25089:1136445] 吃饭====<NSThread: 0x7fb050700ee0>{number = 2, name = (null)}
2016-04-13 16:24:22.102 test[25089:1136445] 上厕所====<NSThread: 0x7fb050700ee0>{number = 2, name = (null)} 

可以看出来当操作方式是dispatch_async时,只有两个队列,一个主线程,一个子线程,在子线程中执行三个方法,所以异步操作是可以创建新线程的,而且操作会顺序执行的,这个非常有用,既不会影响主线程,又可以开启新线程按顺序执行任务。现在把操作方式改为dispatch_sync看一下打印结果:

2016-04-13 17:33:42.131 test[25342:1168870] 读书===<NSThread: 0x7f8118d03bb0>{number = 1, name = main}
2016-04-13 17:33:42.131 test[25342:1168870] 吃饭====<NSThread: 0x7f8118d03bb0>{number = 1, name = main}
2016-04-13 17:33:42.132 test[25342:1168870] 上厕所====<NSThread: 0x7f8118d03bb0>{number = 1, name = main}

可以看出来只有一个线程,也就是主线程,所以证明了dispatch_sync是没有开启新线程的能力的。

二、DISPATCH_QUEUE_CONCURRENT:并行队列

我们再把队列的属性改成DISPATCH_QUEUE_CONCURRENT试试,看下打印结果:

2016-04-13 17:44:38.296 test[25402:1175291] 上厕所====<NSThread: 0x7fdfe8f288a0>{number = 4, name = (null)}
2016-04-13 17:44:38.296 test[25402:1175301] 读书===<NSThread: 0x7fdfe8f2bf10>{number = 2, name = (null)}
2016-04-13 17:44:38.296 test[25402:1175307] 吃饭====<NSThread: 0x7fdfe8e21cd0>{number = 3, name = (null)}

首先,可以看出,当队列的属性是DISPATCH_QUEUE_CONCURRENT时,任务会无序执行的,而且并行队列DISPATCH_QUEUE_CONCURRENT是可以开启新线程的。

得出结果当队列的属性是DISPATCH_QUEUE_CONCURRENT并行队列,操作是异步操作dispatch_async时,会创建多个线程,操作无序执行。但是如果队列钱有其他任务,会等待其他任务执行完成后再执行其他的任务。适合的操作为:既不影响主线程,又不需要顺序执行的操作。

然后,我们再把操作改为dispatch_sync,看下打印结果:

2016-04-13 18:08:17.944 test[25521:1187204] 读书===<NSThread: 0x7fe74ac05610>{number = 1, name = main}
2016-04-13 18:08:17.944 test[25521:1187204] 吃饭====<NSThread: 0x7fe74ac05610>{number = 1, name = main}
2016-04-13 18:08:17.945 test[25521:1187204] 上厕所====<NSThread: 0x7fe74ac05610>{number = 1, name = main}

可以看出,无论队列的方式是串行队列还是并行队列,dispatch_sync同步操作方式都是不会创建新线程的,任务只会在主线程中执行。

三、dispatch_get_global_queue():全局队列

看下面一段代码:
- (void) globalQueue
{
//全局队列,都在主线程中执行,不会死锁,
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"读书===%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"吃饭====%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"上厕所====%@", [NSThread currentThread]);
});
}

结果:

2016-04-13 18:16:18.646 test[25609:1191848] 吃饭====<NSThread: 0x7f91c940db00>{number = 3, name = (null)}
2016-04-13 18:16:18.650 test[25609:1191841] 读书===<NSThread: 0x7f91c9659890>{number = 2, name = (null)}
2016-04-13 18:16:18.646 test[25609:1191855] 上厕所====<NSThread: 0x7f91c940fa50>{number = 4, name = (null)}

全局队列是系统的,无序创建,直接用即可,可以看出,全局队列与并行队列类型,但是调试时,无法确认操作所在队列。
当操作方式为dispatch_sync时,不再做解析,雷同上面。

四、dispatch_get_main_queue():主队列

看下面一段代码:

- (void) mainQueue
{
//直接死锁
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
    NSLog(@"读书===%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"吃饭====%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"上厕所====%@", [NSThread currentThread]);
});
}

结果:

2016-04-13 18:35:50.259 test[25749:1204150] 读书===<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}
2016-04-13 18:35:50.264 test[25749:1204150] 吃饭====<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}
2016-04-13 18:35:50.264 test[25749:1204150] 上厕所====<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}

每一个应用程序中只有一个主队列,直接使用即可无需创建,常常在主队列中更新UI。主队列中的操作都应该自主队列中执行,不存在异步的概念。除非主线程被用户杀掉,否则永远不会结束。

五、dispatch_sync的应用场景(登陆操作)。dispatch_sync会阻塞并行队列的执行,要求某一操作执行完成之后才会执行下一个操作。
- (void) newThread
{
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_CONCURRENT);
__block BOOL logon = NO;
dispatch_sync(q, ^{ //同步
    NSLog(@"模拟耗时操作 %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0f];//停留两秒钟,模仿耗时操作
    NSLog(@"模拟耗时完成 %@", [NSThread currentThread]);
    logon = YES;
});

dispatch_async(q, ^{
    NSLog(@"登录完成的处理 %@", [NSThread currentThread]);
});
}

结果:

2016-04-14 10:47:24.117 test[26976:1276763] 模拟耗时操作 <NSThread: 0x7fe3a8d054e0>{number = 1, name = main}
2016-04-14 10:47:26.119 test[26976:1276763] 模拟耗时完成 <NSThread: 0x7fe3a8d054e0>{number = 1, name = main}
2016-04-14 10:47:26.119 test[26976:1276894] 登录完成的处理 <NSThread: 0x7fe3a8c10f80>{number = 2, name = (null)}
六、dispatch_barrier_async,在并行队列中等待前面的操作执行完成后,才恢复后面的执行状态。
- (void) dispatchBarrierAsync
{
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
    NSLog(@"%@====dispatch-1", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
    NSLog(@"%@=====dispatch-2", [NSThread currentThread]);
});
dispatch_barrier_async(concurrentQueue, ^(){
    NSLog(@"%@======dispatch-barrier", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
    NSLog(@"%@======dispatch-3", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
    NSLog(@"%@======dispatch-4", [NSThread currentThread]);
});
}

结果:

2016-04-14 11:00:34.769 test[27143:1285750] <NSThread: 0x7ff80a70adb0>{number = 3, name = (null)}=====dispatch-2
2016-04-14 11:00:34.769 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}====dispatch-1
2016-04-14 11:00:34.772 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}======dispatch-barrier
2016-04-14 11:00:34.772 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}======dispatch-3
2016-04-14 11:00:34.772 test[27143:1285750] <NSThread: 0x7ff80a70adb0>{number = 3, name = (null)}======dispatch-4
七、dispatch_group_t,当有多个任务时,可以把多个任务放到group里面,group执行完毕后再执行其他任务。
- (void) group
{
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
    
    NSLog(@"task1 begin=====%@", [NSThread currentThread]);
});

dispatch_group_async(group, queue, ^{
    
    NSLog(@"task2 begin=====%@", [NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
    NSLog(@"======================%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
    
    NSLog(@"task3 begin=====%@", [NSThread currentThread]);
});

dispatch_group_async(group, queue, ^{
    
    NSLog(@"task4 begin=====%@", [NSThread currentThread]);
});
}

结果:

2016-04-14 11:35:54.676 test[27339:1300173] task1 begin=====<NSThread: 0x7fe3da606170>{number = 2, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300202] task4 begin=====<NSThread: 0x7fe3da621660>{number = 5, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300167] task2 begin=====<NSThread: 0x7fe3da6213a0>{number = 3, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300178] task3 begin=====<NSThread: 0x7fe3da51f7b0>{number = 4, name = (null)}
2016-04-14 11:35:54.770 test[27339:1300178] ======================<NSThread: 0x7fe3da51f7b0>{number = 4, name = (null)}

可以看出,当所有任务都执行完毕后才执行dispatch_group_notify中的任务。

看完这篇文章,相信大家对GCD有了详细的了解,有问题欢迎大家一起探讨,下班回家吃饭去,哈哈。

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

推荐阅读更多精彩内容

  • 简介 GCD(Grand Central Dispatch)是在macOS10.6提出来的,后来在iOS4.0被引...
    sunmumu1222阅读 858评论 0 2
  • iOS中GCD的使用小结 作者dullgrass 2015.11.20 09:41*字数 4996阅读 20199...
    DanDanC阅读 820评论 0 0
  • 目录(GCD): 关键词 混淆点 场景应用 总结 1. 关键词 线程概念: 独立执行的代码段,一个线程同时间只能执...
    Ryan___阅读 1,264评论 0 3
  • 本篇博客共分以下几个模块来介绍GCD的相关内容: 多线程相关概念 多线程编程技术的优缺点比较? GCD中的三种队列...
    有梦想的老伯伯阅读 1,018评论 0 4
  • 1. GCD简介 什么是GCD呢?我们先来看看百度百科的解释简单了解下概念 引自百度百科:Grand Centra...
    千寻_544f阅读 362评论 0 0