iOS多线程开发之GCD(基础篇)
总纲:
- GCD基本概念
- GCD如何实现
- GCD如何使用
- 队列和任务组合
一、GCD基本概念
GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了⼀种新的方法来进⾏并发程序编写。从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程序将任务切分为多个单一任务,然后提交⾄⼯作队列来并发的或者串⾏的执行。GCD是C实现,⽐NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分 并发任务会像NSOperationQueue那样基于系统负载来合适地并发进⾏,而串⾏行队列同一时间只执行单一任务,GCD的API很大程度上基于block。
GCD并发编程的主要好处归纳
- GCD可用于多核的并行运算
- GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
二、GCD如何实现
GCD主要由队列和任务两部分来实现,苹果官方对GCD是这样说明的:开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。Dispatch Queue是执行处理的等待队列,我们可以通过dispatch_async等API,在block语法中记述想要执行的处理并将其追加到Dispatch Queue中,Dispatch Queue是按照追加的顺序进行处理(先进先出FIFO)。
多线程执行过程就是把任务放在队列中去执行的过程。那么在这里我们首先回顾一下基本概念:
(一)进程/线程、任务/队列
(二)同步/异步、并发/并行
并发不一定等于并行
(三)异步/同步任务 & 并行/串行队列的特点
综上所述,iOS多线程编程使用GCD的最优原则是能不在阻碍主线程(又叫作UI线程)的情况下,开启新的线程(子线程)去处理耗时的操作,以便有效提高程序的执行效率和资源利用率,但是同时开启多个子线程也会引发许多其他的问题,如资源竞争、死锁、内存损耗等,所以要注意,这篇文章只是介绍GCD的使用,因此可能产生的问题我将会在这个系列后续篇章做介绍。
GCD并发编程产生的作用归纳(考虑线程安全,不死锁的情况下效果):
能开启新的线程(子线程)
多个任务可以同时进行
不会阻塞主线程(又叫作UI线程)影响UI事件
三、GCD如何使用
开发者要做的只是定义想执行的任务并追加到适当的队列(Dispatch Queue)中
1、创建队列(Dispatch Queue)
第一种:通过GCD的API的dispatch_queue_create函数生成Dispatch Queue
// 创建串行队列 dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);// 创建并发队列 dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_CONCURRENT);
另外需要注意的点是:虽然有ARC编译器自动管理内存这一优秀技术,但生成的Dispatch Queue必须由程序员主动释放。
// 释放 dispatch_release(exampleSerialDispatchQueue) // 持有 dispatch_retain(exampleSerialDispatchQueue)
第二种:直接使用系统提供的标准Dispatch Queue :Main Dispatch Queue和Global Dispatch Queue
(1)Main Dispatch Queue:主线程中执行的Dispatch Queue,也就是Serial Dispatch Queue(串行队列),可以通过dispatch_get_main_queue()来获取。
dispatch_queue_t mainDispatchQueue = dispath_get_main_queue();
(2) Global Dispatch Queue: 全局并发队列(Concurrent Dispatch Queue),GCD默认提供了全局的并发队列,可以通过dispatch_get_global_queue()获取。
// 高优先级 dispatch_queue_t globalDispatchQueueHigh = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0) // 默认优先级 dispatch_queue_t globalDispatchQueueDefault = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) // 低优先级 dispatch_queue_t globalDispatchQueueLow = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0) // 后台优先级 dispatch_queue_t globalDispatchQueueBackgroud = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_GACKGROUND,0)
一般来说,主线程(又叫做UI线程)主要处理UI事件,耗时操作(如I/O,数据库访问,网络资源加载等)则放在子线程中,等子线程操作完成后再回到主线程进行UI刷新,以下例举使用Main Dispatch Queue和Global Dispatch Queue的源码:
- (void)testMainGlobalDispatchQueue{// 创建全局并发队列,默认优先级dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 可并行处理的任务(耗时操作)代码放在这里// 获取主线程,处理UI事件dispatch_async(dispatch_get_main_queue(), ^{// UI事件 });}); }
2、创建任务
// 同步执行任务创建方法 dispatch_sync(queue, ^{NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码 });// 异步执行任务创建方法 dispatch_async(queue, ^{NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码 });
四、队列任务组合
根据(二)中描述,GCD由队列和任务两部分组成,队列分为串行队列、并行队列、主队列,任务可分为同步和异步任务,这样可将队列与任务组合如下:
1、并行队列 & 异步执行
- (void) asyncConcurrentTask {NSLog(@"asyncConcurrentTask---start");dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{NSLog(@"Task1------%@",[NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task2------%@",[NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task3------%@",[NSThread currentThread]);});NSLog(@"asyncConcurrentTask---end"); }
打印结果:
2017-07-02 11:13:10.963 Test[6266:2853210] asyncConcurrentTask---start 2017-07-02 11:13:10.963 Test[6266:2853210] asyncConcurrentTask---end 2017-07-02 11:13:10.963 Test[6266:2854044] Task3------<NSThread: 0x60800007cdc0>{number = 5, name = (null)} 2017-07-02 11:13:10.963 Test[6266:2854059] Task2------<NSThread: 0x60800007d1c0>{number = 4, name = (null)} 2017-07-02 11:13:10.963 Test[6266:2854041] Task1------<NSThread: 0x600000074e80>{number = 3, name = (null)}
结论:
(1) 开启了新线程
(2) 任务之间不需要排队,且具有同时被执行的权利
2、并行队列 & 同步执行
- (void)syncConcurrentTask {dispatch_queue_t queue = dispatch_queue_create("com.beck.wang.queue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"syncConcurrentTask---start---");dispatch_sync(queue, ^{NSLog(@"Task1---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task2---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task3---%@", [NSThread currentThread]);});NSLog(@"syncConcurrentTask---end---"); }
打印结果:
2017-07-02 11:25:04.725 Test[6385:2940867] syncConcurrentTask---start--- 2017-07-02 11:25:04.725 Test[6385:2940867] Task1---<NSThread: 0x608000067540>{number = 1, name = main} 2017-07-02 11:25:04.726 Test[6385:2940867] Task2---<NSThread: 0x608000067540>{number = 1, name = main} 2017-07-02 11:25:04.726 Test[6385:2940867] Task3---<NSThread: 0x608000067540>{number = 1, name = main} 2017-07-02 11:25:04.726 Test[6385:2940867] syncConcurrentTask---end---
结论:
(1) 不开启了新线程
(2) 任务之间需要排队,按照追加顺序执行
3、串行队列 & 异步执行
- (void)asyncSerialTask {dispatch_queue_t queue = dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);NSLog(@"asyncSerialTask---start---");dispatch_async(queue, ^{NSLog(@"Task1---%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task2---%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task3---%@", [NSThread currentThread]);});NSLog(@"asyncSerialTask---end---"); }
打印结果:
2017-07-02 11:36:27.068 Test[6557:3008079] asyncSerialTask---start--- 2017-07-02 11:36:27.068 Test[6557:3008079] asyncSerialTask---end--- 2017-07-02 11:36:27.068 Test[6557:3008342] Task1---<NSThread: 0x600000071e00>{number = 3, name = (null)} 2017-07-02 11:36:27.069 Test[6557:3008342] Task2---<NSThread: 0x600000071e00>{number = 3, name = (null)} 2017-07-02 11:36:27.069 Test[6557:3008342] Task3---<NSThread: 0x600000071e00>{number = 3, name = (null)}
结论:
(1) 开启了新线程
(2) 任务之间需要排队,按照追加顺序执行
4、串行队列 & 同步执行
- (void)syncSerialTask {dispatch_queue_t queue = dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);NSLog(@"syncSerialTask---start---");dispatch_sync(queue, ^{NSLog(@"Task1---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task2---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task3---%@", [NSThread currentThread]);});NSLog(@"syncSerialTask---end---"); }
打印结果:
2017-07-02 13:17:48.948 Test[7238:3192943] syncSerialTask---start--- 2017-07-02 13:17:48.948 Test[7238:3192943] Task1---<NSThread: 0x600000076640>{number = 1, name = main} 2017-07-02 13:17:48.949 Test[7238:3192943] Task2---<NSThread: 0x600000076640>{number = 1, name = main} 2017-07-02 13:17:48.949 Test[7238:3192943] Task3---<NSThread: 0x600000076640>{number = 1, name = main} 2017-07-02 13:17:48.949 Test[7238:3192943] syncSerialTask---end---
结论:
(1) 不开启了新线程
(2) 任务之间需要排队,按照追加顺序执行
5、主队列 & 异步执行
- (void)asyncMainTask {dispatch_queue_t queue = dispatch_get_main_queue();NSLog(@"asyncMainTask---start---");dispatch_async(queue, ^{NSLog(@"Task1---%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task2---%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"Task3---%@", [NSThread currentThread]);});NSLog(@"asyncMainTask---end---"); }
打印结果:
2017-07-02 13:19:36.828 Test[7272:3206224] asyncMainTask---start--- 2017-07-02 13:19:36.828 Test[7272:3206224] asyncMainTask---end--- 2017-07-02 13:19:36.834 Test[7272:3206224] Task1---<NSThread: 0x608000072480>{number = 1, name = main} 2017-07-02 13:19:36.834 Test[7272:3206224] Task2---<NSThread: 0x608000072480>{number = 1, name = main} 2017-07-02 13:19:36.834 Test[7272:3206224] Task3---<NSThread: 0x608000072480>{number = 1, name = main}
结论:
(1) 不开启了新线程
(2) 任务之间需要排队,按照追加顺序执行
6、主队列 & 同步执行
- (void)syncMainTask{dispatch_queue_t queue = dispatch_get_main_queue();NSLog(@"syncMainTask---start---");dispatch_sync(queue, ^{NSLog(@"Task1---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task2---%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"Task3---%@", [NSThread currentThread]);});NSLog(@"syncMainTask---end---"); }
打印结果:
2017-07-02 13:22:31.860 Test[7335:3230988] syncMainTask---start---
结论:
发生死锁,程序崩溃。
好了GCD系列的上篇就写到这里,我将在后续系列中详细介绍GCD的队列系列和用法,以及使用GCD可能造成的问题及解决方案,水平有限,有不对的地方还望批评指正!
转载于:https://www.cnblogs.com/beckwang0912/p/7100201.html
iOS多线程开发之GCD(基础篇)相关推荐
- Swift5多线程系列一GCD基础篇
Swift5多线程系列-基础概念篇 iOS开发,多线程开发常用GCD,swift也如是;swift的GCD,使用比OC上更加简单易上手; GCD基础篇目录 Swift5多线程系列-基础概念篇 基础篇 ...
- iOS多线程开发之NSThread
一.NSThread基本概念 NSThread是基于线程使用,轻量级的多线程编程方法(相对GCD和NSOperation),一个NSThread对象代表一个线程,需要手动管理线程的生命周期,处理线程同 ...
- 前端开发之JavaScript基础篇一
主要内容: 1.JavaScript介绍 2.JavaScript的引入方法和输出及注释 3.javaScript变量和命名规则 4.五种基本数据类型 5.运算符 6.字符串处理 7.数据类型转换 ...
- 前端开发之JavaScript基础篇四
主要内容: 1.定时器 2.正则表达式入门 3.元字符 4.正则表达式实战运用 一.定时器 javaScript里主要使用两种定时器,分别是:setInterval()和setTimeout(). 1 ...
- IOS开发之UI基础LOL英雄展示-15
IOS开发之UI基础LOL英雄展示-15 // // ViewController.m // 15-英雄展示-单组数据 // // Created by 鲁军 on 2021/2/3. //#impo ...
- ios c语言调用oc方法,ios开发之OC基础-类和对象(示例代码)
本系列的文章主要来自于个人在学习前锋教育-欧阳坚老师的iOS开发教程之OC语言教学视频所做的笔记,边看视频,边记录课程知识点.建议大家先过一遍视频,在看视频的过程中记录知识点关键字,把把握重点,然后再 ...
- ios开发之OC基础-类和对象
ios开发之OC基础-类和对象 本系列的文章主要来自于个人在学习前锋教育-欧阳坚老师的iOS开发教程之OC语言教学视频所做的笔记,边看视频,边记录课程知识点.建议大家先过一遍视频,在看视频的过程中记录 ...
- iOS 多线程:『GCD』详尽总结
原文链接:www.jianshu.com/p/2d57c7201- 感谢大家对这篇文章的喜欢和支持.为了不辜负大家的喜欢,也为了更好的让大家了解 iOS 多线程,以及 GCD 的相关知识,我对这篇文章 ...
- 电影天堂APP项目开发之Python爬虫篇,共18课时/5时33分
电影天堂APP项目开发之Python爬虫篇,共18课时/5时33分,是电影天堂APP项目开发课程的第一篇章,讲解使用requests和bs4库,爬取和解析电影天堂网站数据,并讲数据保存到SQLite数 ...
最新文章
- 数据结构笔记--二叉查找树概述以及java代码实现
- java redis多主多备_java 集成Redis 一主多从
- Java注解(Annotation)详解
- C#中使用MD5对用户密码加密与解密
- 【结论】Number(jzoj(gz) 1781)
- jsp页面,使用Struts2标签,传递和获取Action类里的参数,注意事项。s:a actions:iterators:paramognl表达式...
- 驱动框架3——在内核中添加或去除某个驱动
- 海量结构化数据解决方案-表格存储场景解读
- Windows平台下的Redis集群搭建(简单有效)
- [OC]数据库的使用--数据读取
- 网易云音乐与腾讯闹掰;今日头条下架万条短视频;美团打车或将被吊证| CSDN 极客头条
- Yii 自定义模型路径
- iOS视频播放器MPMoviePlayerController
- SolidWorks钣金零件导出dxf排版拉丝方向C#二次开发
- 利用百度图像处理API接口实现人脸融合
- VCIP2020:SCC编码工具的优化实现
- 数组中的最长山脉java实现
- 项目经理的工具箱---走出软件作坊:三五个人十来条枪 如何成为开发正规军(三)...
- 圆周率小数点后1千位(附计算圆周率源代码)
- 数据结构入门----赫夫曼Huffman树及其应用