尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
「iOS」GCD
「iOS」GCD文章目录「iOS」GCD一、基础知识1. 队列2. 同步、异步二、iOS的多线程方案三、GCD1. 优势2. 使用四、总结一、基础知识1. 队列定义队列又称为伫列queue是先进先出的线性表在具体应用中通常用链表或者数组来实现。装载线程任务的队形结构。队列只允许在后端称为rear进行插入操作在前端称为front进行删除操作。队列的操作方式和堆栈类似唯一的区别在于队列只允许新数据在后端进行添加。**类型**队列的类型决定了任务的执行方式并发、串行队列包括以下几种并发队列 线程执行可以同时一起进行执行,不需要上一个执行完就能执行下一个的。串行队列 线程执行只能依次逐一先后有序的执行,等待上一个执行完再执行下一个。主队列绑定主线程所有任务都在主线程中执行有经过特殊处理的串行队列。全局队列系统提供的并发队列。2. 同步、异步同步sync 只能在当前线程按先后顺序依次执行任务不具备开启新线程的能力。异步async 在新的线程中执行任务具备开启新线程的能力。二、iOS的多线程方案pthread是线程的POSIX标准是一套通用的多线程API可以在Unix/Linux/Windows等平台跨平台使用。iOS中基本不使用。NSThread苹果封装的面向对象的线程类可以直接操作线程比起GCDNSThread效率更高由程序员自行创建当线程中的任务执行完毕后线程会自动退出程序员也可手动管理线程的生命周期。使用频率较低。GCD全称Grand Central Dispatch由C语言实现是苹果为多核的并行运算提出的解决方案CGD会自动利用更多的CPU内核自动管理线程的生命周期程序员只需要告诉GCD需要执行的任务无需编写任何管理线程的代码。GCD也是iOS使用频率最高的多线程技术。NSOperation基于GCD封装的面向对象的多线程技术常配合NSOperationQueue使用使用频率较高。三、GCD1. 优势GCD是苹果公司为多核的并行运算提出的解决方案GCD会自动利用更多的CPU内核比如双核、四核GCD会自动管理线程的生命周期创建线程、调度任务、销毁线程程序员只需要告诉GCD想要执行什么任务不需要编写任何线程管理代码2. 使用同步执行API//queue队列 block任务dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);异步执行//queue队列 block任务dispatch_async(dispatch_queue_t queue,dispatch_block_t block);dispatch_block_t任务无参数、无返回值的 Block 回调用于存放具体需要执行的线程任务底层定义如下typedefvoid(^dispatch_block_t)(void);dispatch_queue_t队列任务存放的队列容器。自定义队列通过dispatch_queue_create创建参数分别为队列名称、队列类型其中串行队列宏DISPATCH_QUEUE_SERIAL等价于 NULL传 NULL 即为串行队列。我们已经知道队列在iOS中主要分为4种自定义的队列都是调用dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr)方法来进行创建两个参数分别为自定义队列名称和队列类型。其中串行队列DISPATCH_QUEUE_SERIAL为宏定义的NULL所以传NULL也表示为串行队列。现在我们来看这2种执行模式3种队列是相互搭配是什么效果同步 (主队列或自定义串行队列)死锁-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1:%,[NSThread currentThread]);dispatch_queue_t queuedispatch_get_main_queue();dispatch_sync(queue,^{NSLog(任务2,[NSThread currentThread]);});NSLog(任务3:%,[NSThread currentThread]);}运行结果打印任务1后死锁崩溃原因分析主队列是串行队列遵循 FIFO 规则。当前viewDidLoad本身是主队列的任务未执行完毕此时通过同步方式向主队列新增任务2同步执行会阻塞主线程等待任务2执行完成。但任务2需要等待viewDidLoad原有任务执行完毕才能执行二者相互等待最终形成死锁。异步 (主队列或自定义串行队列)-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1:%,[NSThread currentThread]);dispatch_queue_t queuedispatch_get_main_queue();dispatch_async(queue,^{NSLog(任务2:%,[NSThread currentThread]);});NSLog(任务3:%,[NSThread currentThread]);}运行结果任务1:_NSMainThread: 0x60000170c000{number 1, name main} 任务3:_NSMainThread: 0x60000170c000{number 1, name main} 任务2:_NSMainThread: 0x60000170c000{number 1, name main}异步执行不会阻塞当前主线程主线程执行完任务1后无需等待任务2完成直接执行任务3。主队列是串行队列所有任务仍在主线程排队执行因此任务3执行完成后再执行任务2不会开启新线程、不会死锁。同步(全局队列或者自定义并发队列) 顺序执行、无新线程-(void)viewDidLoad{[superviewDidLoad];dispatch_queue_t queuedispatch_get_global_queue(0,0);dispatch_sync(queue,^{for(inti0;i3;i){NSLog(任务一%,[NSThread currentThread]);}});dispatch_sync(queue,^{for(inti0;i3;i){NSLog(任务二%,[NSThread currentThread]);}});}运行结果任务一_NSMainThread: 0x600001704000{number 1, name main} 任务一_NSMainThread: 0x600001704000{number 1, name main} 任务一_NSMainThread: 0x600001704000{number 1, name main} 任务二_NSMainThread: 0x600001704000{number 1, name main} 任务二_NSMainThread: 0x600001704000{number 1, name main} 任务二_NSMainThread: 0x600001704000{number 1, name main}同步执行本身不具备开启新线程的能力任务直接在主线程执行且会阻塞线程必须等待上一个任务完成才会执行下一个任务。虽然队列是并发队列但受同步执行特性限制任务只能顺序执行且不会阻塞主线程正常运行。异步(全局队列或者自定义并发队列)并发执行、开启新线程-(void)viewDidLoad{[superviewDidLoad];dispatch_queue_t queuedispatch_get_global_queue(0,0);dispatch_async(queue,^{for(inti0;i3;i){NSLog(任务一%,[NSThread currentThread]);}});dispatch_async(queue,^{for(inti0;i3;i){NSLog(任务二%,[NSThread currentThread]);}});}运行结果任务二NSThread: 0x600001726340{number 6, name (null)} 任务一NSThread: 0x60000170dd00{number 5, name (null)} 任务二NSThread: 0x600001726340{number 6, name (null)} 任务一NSThread: 0x60000170dd00{number 5, name (null)} 任务二NSThread: 0x600001726340{number 6, name (null)} 任务一NSThread: 0x60000170dd00{number 5, name (null)}可以看出任务1和任务2交错执行并非同步执行那样执行完任务1再执行任务2。而且通过线程编号可以看出的确开启了新的线程。说明异步执行具备开启新线程的能力。但是通过上面异步主队列的打印结果我们可以发现在主队列时异步执行也并没有开启新的线程而仍然是同一个主线程。说明如果在主队列中异步执行是不会开启新线程的原因是因为主队列是串行队列必须执行完一个任务再执行另一个任务异步执行只是没有造成堵塞但是在主队列还是是要一步步走的。同一串行队列嵌套-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1);dispatch_queue_t queuedispatch_queue_create(myQueue,DISPATCH_QUEUE_SERIAL);dispatch_async(queue,^{NSLog(任务2);dispatch_sync(queue,^{NSLog(任务3);});NSLog(任务4);});NSLog(任务5);}运行结果任务1 任务5 任务2 然后崩溃这里造成死锁崩溃的原因和上面同步串行队列的原因一样。由于主队列是串行的所以代码必然是从上到下依次执行的。打印完任务1后执行dispatch_async为异步不会阻塞线程但是会加入自定义的串行队列中所以会执行任务5接着执行异步代码块中逻辑打印任务2接着执行dispatch_sync代码块但是由于其是同步串行队列中已经有了dispatch_async任务未执行完毕此时dispatch_sync阻塞当前线程等待任务3执行造成了相互等待所以就死锁崩溃了不同串行队列嵌套-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1);dispatch_queue_t queuedispatch_queue_create(myQueue,DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue2dispatch_queue_create(myQueue2,DISPATCH_QUEUE_SERIAL);dispatch_async(queue,^{NSLog(任务2);dispatch_sync(queue2,^{NSLog(任务3);});NSLog(任务4);});NSLog(任务5);}运行结果任务1任务5任务2任务3任务4当嵌套执行时同步异步在不同的串行队列执行并不会造成死锁崩溃。而是按照串行的顺序执行代码。这事因为dispatch_sync阻塞的并不是当前的线程而是其他的线程所以不会造成死锁等待。同一并发队列嵌套-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1);dispatch_queue_t queuedispatch_queue_create(myQueue,DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue,^{NSLog(任务2);dispatch_sync(queue,^{NSLog(任务3);});NSLog(任务4);});NSLog(任务5);}运行结果任务1任务5任务2任务3任务4主线程执行任务1之后需要异步dispatch_async执行任务2所以先执行主线程的任务5然后执行任务2接着需要在并发队列中同步dispatch_sync执行任务3,所以会造成阻塞等待其执行完成然后执行并发队列中的任务4。不同并发、串行队列嵌套-(void)viewDidLoad{[superviewDidLoad];NSLog(任务1);dispatch_queue_t queuedispatch_queue_create(myQueue,DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue2dispatch_queue_create(myQueue2,DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue,^{NSLog(任务2);dispatch_sync(queue2,^{NSLog(任务3);});NSLog(任务4);});NSLog(任务5);}运行结果任务1任务5任务2任务3任务4创建了新的队列所以是不会造成当前队列的阻塞的。四、总结同步执行sync无新开线程能力阻塞当前线程任务严格顺序执行同一串行队列嵌套同步任务必然触发死锁异步执行async具备新开线程能力不阻塞当前线程在并发队列中任务无序并行执行在串行队列中任务有序排队执行主队列特殊规则无论同步还是异步执行均不会开启新线程同步执行会死锁异步执行仅延迟执行、不崩溃队列嵌套核心同一串行队列嵌套同步任务必死锁不同队列、并发队列嵌套均不会触发死锁
RELATED

相关推荐

计算机毕业设计选题推荐:基于大数据的杭州亚运会社交媒体互动数据可视化分析|毕业设计选题|计算机毕设|选题推荐|毕设指导|项目定制|源码|高质量项目

计算机毕业设计选题推荐:基于大数据的杭州亚运会社交媒体互动数据可视化分析|毕业设计选题|计算机毕设|选题推荐|毕设指导|项目定制|源码|高质量项目

✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

📅 2026/9/28 21:08:05
大模型加载太慢怎么办,用镜像站让 Qwen3-VL 跑得飞起

大模型加载太慢怎么办,用镜像站让 Qwen3-VL 跑得飞起

被网速卡住的 AI 开发:Qwen3-VL 加载慢的破局之道在多模态大模型落地的过程中,最让人头疼的往往不是模型架构的复杂,也不是显存资源的紧缺,而是那个看似简单却极度消耗耐心的环节:模型权重下载。当你兴致勃勃地准备在本…

📅 2026/9/28 21:08:05
AI Agent知识获取管道:TypeScript从零搭建RAG实战

AI Agent知识获取管道:TypeScript从零搭建RAG实战

1. 为什么知识获取管道是 AI Agent 从玩具走向工具的分水岭做 AI Agent 开发的人,大概都经历过这样一个阶段:Demo 跑得飞起,一旦接入真实业务数据就立刻露馅。你问它公司内部的报销标准,它一本正经地编出一个数字;你让…

📅 2026/9/28 21:08:05
MORE NEWS

更多资讯

📰

Yolov5目标检测Web部署实战:Flask框架从封装到生产落地

简介:面向需要在Web端快速上线YOLOv5目标检测能力的开发者,这份资源提供了一个完整的Flask部署项目,覆盖模型加载、图片上传、推理结果JSON化及简单前端交互,适合具备基础Python和深度学习概念、希望避开从零搭建环境的学习者。压…

📰

SpringBoot餐厅等位叫号系统:Redis队列与WebSocket实时推送实战

如果你正在找Java后端的练手项目,或者准备毕业设计,SpringBoot的餐厅等位叫号系统大概率已经在你的候选清单里了。这个项目看着不起眼,但里面塞满了面试高频考点——队列、并发控制、状态机、实时推送,随便拎一个出来都能聊上十分…

📰

VCF部署NSX超时排查与延长超时实操指南

先别急着怀疑自己的操作,VCF 部署 NSX 一直卡在某个步骤最后报“操作超时”,这事在不少机房都发生过。我自己第一次在 VCF 管理域里做 NSX 集成时,整整一个下午都在跟“超时”两个字搏斗,后来发现根因不只是时间给得不够&#xff…

📰

openclaw本地部署实战:让Agent框架接管Chrome浏览器自动化

1. 为什么是openclaw:从"聊天机器人"到"浏览器代理"的关键转变1.1 openclaw的定位:本地部署的Agent框架先坦白我为什么开始折腾openclaw。上个月我接手了一个运营后台,每天需要登录、点导出、改文件名、传到协作文档&…

📰

SpringBoot+Vue高校入校审批系统实战指南

简介:本资源是一套面向计算机专业本科生的高分毕业设计实战项目,聚焦高校入校申报审批业务场景,采用SpringBoot后端Vue前端的主流全栈技术架构,完整实现用户管理、申报提交、多级审批、数据统计与系统配置等核心功能,适…

📰

能源行业“借刀杀人”式钓鱼攻击:信任链利用与纵深防御实战指南

能源行业这两年挨的打,我看了都替他们肉疼。身边好几个做电力、油气、港口能源项目的朋友,最怕接到的不是设备故障电话,而是“我们值班员点了一封邮件,然后调度系统整个网络都不对了”这种消息。而这类事故背后,几乎都…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬