iOS-GCD使用详解
前言
对初学者来说,GCD似乎是一道迈不过去的坎,很多人在同步、异步、串行、并行和死锁这几个名词的漩涡中渐渐放弃治疗。本文将使用图文表并茂的方式给大家形象地解释其中的原理和规律。
线程、任务和队列的概念

异步、同步 & 并行、串行的特点

一条重要的准则
一般来说,我们使用GCD的最大目的是在新的线程中同时执行多个任务,这意味着我们需要两项条件:
- 能开启新的线程 
- 任务可以同时执行 
- 结合以上两个条件,也就等价“开启新线程的能力 + 任务同步执行的权利”,只有在满足能力与权利这两个条件的前提下,我们才可以在同时执行多个任务。 
所有组合的特点

(一)异步执行 + 并行队列
实现代码:
//异步执行 + 并行队列
- (void)asyncConcurrent{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT); NSLog(@"---start---"); //使用异步函数封装三个任务
dispatch_async(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
}); NSLog(@"---end---");
}
打印结果:
| 1 2 3 4 5 | ---start---  ---end---  任务3---{number = 5, name = (null)}  任务2---{number = 4, name = (null)}  任务1---{number = 3, name = (null)} | 
解释
- 异步执行意味着 - 可以开启新的线程 
- 任务可以先绕过不执行,回头再来执行 
 
- 并行队列意味着 - 任务之间不需要排队,且具有同时被执行的“权利” 
 
- 两者组合后的结果 - 开了三个新线程 
- 函数在执行时,先打印了start和end,再回头执行这三个任务 
- 这三个任务是同时执行的,没有先后,所以打印结果是“任务3-->任务2-->任务1” 
 
步骤图

(二)异步执行 + 串行队列
实现代码:
//异步执行 + 串行队列
- (void)asyncSerial{
//创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL); NSLog(@"---start---");
//使用异步函数封装三个任务
dispatch_async(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
});
NSLog(@"---end---");
}
打印结果:
| 1 2 3 4 5 |  ---start--- ---end---任务1---{number = 3, name = (null)}任务2---{number = 3, name = (null)}任务3---{number = 3, name = (null)} | 
解释
- 异步执行意味着 - 可以开启新的线程 
- 任务可以先绕过不执行,回头再来执行 
 
- 串行队列意味着 - 任务必须按添加进队列的顺序挨个执行 
 
- 两者组合后的结果 - 开了一个新的子线程 
- 函数在执行时,先打印了start和end,再回头执行这三个任务 
- 这三个任务是按顺序执行的,所以打印结果是“任务1-->任务2-->任务3” 
 
步骤图

(三)同步执行 + 并行队列
实现代码:
//同步执行 + 并行队列
- (void)syncConcurrent{
//创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT); NSLog(@"---start---");
//使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
});
NSLog(@"---end---");
}
打印结果:
| 1 2 3 4 5 | ---start---  任务1---{number = 1, name = main}  任务2---{number = 1, name = main}  任务3---{number = 1, name = main}  ---end--- | 
解释
- 同步执行执行意味着 - 不能开启新的线程 
- 任务创建后必须执行完才能往下走 
 
- 并行队列意味着 - 任务必须按添加进队列的顺序挨个执行 
 
- 两者组合后的结果 - 所有任务都只能在主线程中执行 
- 函数在执行时,必须按照代码的书写顺序一行一行地执行完才能继续 
 
- 注意事项 - 在这里即便是并行队列,任务可以同时执行,但是由于只存在一个主线程,所以没法把任务分发到不同的线程去同步处理,其结果就是只能在主线程里按顺序挨个挨个执行了 
 
步骤图

(四)同步执行+ 串行队列
实现代码:
- (void)syncSerial{
    //创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);
    NSLog(@"---start---");
    //使用异步函数封装三个任务
    dispatch_sync(queue, ^{
        NSLog(@"任务1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印结果:
| 1 2 3 4 5 |   ---start---  任务1---{number = 1, name = main}  任务2---{number = 1, name = main}  任务3---{number = 1, name = main}  ---end--- | 
解释
- 这里的执行原理和步骤图跟“同步执行+并发队列”是一样的,只要是同步执行就没法开启新的线程,所以多个任务之间也一样只能按顺序来执行, 
(五)异步执行+主队列
实现代码:
- (void)asyncMain{
    //获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"---start---");
    //使用异步函数封装三个任务
    dispatch_async(queue, ^{
        NSLog(@"任务1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印结果:
| 1 2 3 4 5 |   ---start---  ---end---  任务1---{number = 1, name = main}  任务2---{number = 1, name = main}  任务3---{number = 1, name = main} | 
解释
- 异步执行意味着 - 可以开启新的线程 
- 任务可以先绕过不执行,回头再来执行 
 
- 主队列跟串行队列的区别 - 队列中的任务一样要按顺序执行 
- 主队列中的任务必须在主线程中执行,不允许在子线程中执行 
 
- 以上条件组合后得出结果: - 所有任务都可以先跳过,之后再来“按顺序”执行 
 
步骤图

(六)同步执行+主队列(死锁)
实现代码:
- (void)syncMain{
    //获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"---start---");
    //使用同步函数封装三个任务
    dispatch_sync(queue, ^{
        NSLog(@"任务1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}
打印结果:
| 1 |   ---start--- | 
解释
- 主队列中的任务必须按顺序挨个执行 
- 任务1要等主线程有空的时候(即主队列中的所有任务执行完)才能执行 
- 主线程要执行完“打印end”的任务后才有空 
- “任务1”和“打印end”两个任务互相等待,造成死锁 
步骤图

写在结尾的话
以上就是我对GCD的基础知识和几种组合的理解,如果觉得我的博客写得还可以,欢迎关注我的博客,本人将长期为大家推出高质量的技术博客。当然,如果觉得我哪里理解有错的,也可以留下你的评论。
iOS-GCD使用详解的更多相关文章
- iOS开发——GCD多线程详解
		GCD多线程详解 1. 什么是GCD Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,简单来说,GCD就是iOS一套解决多线程的机制,使用GCD能够最大限度简化多线程 ... 
- iOS应用开发详解
		<iOS应用开发详解> 基本信息 作者: 郭宏志 出版社:电子工业出版社 ISBN:9787121207075 上架时间:2013-6-28 出版日期:2013 年7月 开本:16开 ... 
- 转载]IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本 )
		原文地址:IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本作者:佐佐木小次郎 因为最近项目上要用有关LBS的功能.于是我便做一下预研. 一般说来LBS功能一般分为两块:一块是地理 ... 
- iOS中-Qutarz2D详解及使用
		在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ... 
- iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
		前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ... 
- iOS开发——Block详解
		iOS开发--Block详解 1. Block是什么 代码块 匿名函数 闭包--能够读取其他函数内部变量的函数 函数变量 实现基于指针和函数指针 实现回调的机制 Block是一个非常有特色的语法,它可 ... 
- iOS开发:详解Objective-C runTime
		Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎 ... 
- 了解iOS消息推送一文就够:史上最全iOS Push技术详解
		本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ... 
- iOS开发者证书-详解
		iOS开发者证书-详解/生成/使用 本文假设你已经有一些基本的Xcode开发经验, 并注册了iOS开发者账号. 相关基础 加密算法 现代密码学中, 主要有两种加密算法: 对称密钥加密 和 公开密钥加密 ... 
- iOS开发-Runtime详解
		iOS开发-Runtime详解 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [recei ... 
随机推荐
- BlackLowKey主题CSS
			/* Minification failed. Returning unminified contents. (151,61): run-time error CSS1062: Expected se ... 
- MVC5 下拉框(多选)
			1.Model [Display(Name = "职位")] [Required] public int[] job { get; set; } //职位属性 public IEn ... 
- LaTeX 修订
			LaTeX多人协同编辑的时候,修订起来与word相比较而言麻烦一些.不过随着技术的发展和需求的增多,会有越来越多的工具支持LaTeX的修订. (1)在线LaTeX ShareLaTeX是一个很优秀的在 ... 
- [转]最全Redis面试题整理
			此为转载文章,仅做记录使用,方便日后查看,原文链接:http://www.bieryun.com/3405.html 1.什么是Redis? 答:Redis全称为:Remote Dictionary ... 
- Spring课程 Spring入门篇 5-1 aop基本概念及特点
			概念: 1 什么是aop及实现方式 2 aop的基本概念 3 spring中的aop 1 什么是aop及实现方式 1.1 aop,面向切面编程,比如:唐僧取经需要经过81难,多一难少一难都不行.孙悟空 ... 
- oracle学习篇十二:索引
			索引: 查询User_indexes可以获取有关用户已创建的索引的详细信息. 查询User_ind_partitions可以获取有关用户已创建的分区索引的详细信息. 查询User_ind_column ... 
- VUE-地区选择器(V-Distpicker)
			V - Distpicker 地区选择器环境问题不多说,自己看文档,主要讲一下在实际使用过程中如何将下拉框的值赋值到对象属性上.文档: https://distpicker.pigjian.com/g ... 
- csharp:汉字转带拼音声调
			{ ... 
- 【转载】Navicat Premium 12安装与激活
			原文地址 https://www.jianshu.com/p/5f693b4c9468#comment-20147185感谢作者的无私奉献,无意侵权,如需删除请联系我!所提供的激活文件理论支持Navi ... 
- ezdpl:完全依赖脚本和ssh的自动化部署方案
			ezdpl是easy deployment的简写,使用简单的ssh和shell脚本来部署.升级.回滚和重新配置linux服务器. 重要提示:警告:这个项目还处于测试过程中,请仔细阅读说明,并且自己承担 ... 
