iOS多线程编程
dispatch_async(queue, ^{
NSLog(@"想执行的任务";
});
编程人员在Block语法中记述想执行的处理并将其追加到Dispatch Queue中。Dispatch Queue按照追加顺序(先进先出 FIFO,First-In-First-Out)执行处理。

// 自定义串行队列,将任务ABC加到串行队列中,顺序执行
dispatch_queue_t customSerialQueue = dispatch_queue_create("test.wangdachui.MyCustomQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(customSerialQueue, ^{
NSLog(@"customSerialQueue-A");
});
dispatch_async(customSerialQueue, ^{
NSLog(@"customSerialQueue-B");
});
dispatch_async(customSerialQueue, ^{
NSLog(@"customSerialQueue-C");
});
// 由于上面是异步执行操作,所以很难知道下面的打印和上面异步操作中的打印谁先谁后
NSLog(@"customSerialQueue-D"); //多个串行队列并行执行,系统对于一个serialQueue就只生成并使用一个线程。如果生成2000个serialQueue,那么就生成2000个线程
dispatch_queue_t customSerialQueue1 = dispatch_queue_create("test.wangdachui.MyCustomQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t customSerialQueue2 = dispatch_queue_create("test.wangdachui.MyCustomQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t customSerialQueue3 = dispatch_queue_create("test.wangdachui.MyCustomQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(customSerialQueue1, ^{
NSLog(@"customSerialQueue1-A");
});
dispatch_async(customSerialQueue2, ^{
NSLog(@"customSerialQueue2-B");
});
dispatch_async(customSerialQueue3, ^{
NSLog(@"customSerialQueue3-C");
});
//注意:过多使用多线程,就会消耗大量内存问题,引起大量的上下文切换,大幅度降低系统的响应性能
并行队列(Concurrent Dispatch Queue):
iOS和OS X的核心--XNU内核决定应当使用的线程数,并只生成所需的线程执行处理。另外,当处理结束,应当执行的处理数减少时,XNU内核会结束不再需要的线程。XNU内核仅使用Concurrent Dispatch Queue便可以完美地管理并行执行多个处理的线程。
假设准备4个Concurrent Dispatch Queue 用线程。首先blk0在线程0中开始执行,接着blk1在线程1中、blk2在线程2中、blk3在线程3中开始执行。线程0中blk0执行结束后开始执行blk4,由于线程1中blk1的执行没有结束,因此线程2中blk2执行结束后开始执行blk5,就这样循环往复。
像这样在Concurrent Dispatch Queue中执行处理时,执行顺序会根据处理内容和系统状态发生改变。
为了说明线程分配原理,这里假设线程数为4,实测iOS11线程数可达20个,所以想测试的同学,在并发队列中必须追加20个以上的任务
对于Concurrent Dispatch Queue来说,不管生成多少,由于XNU内核只使用有效管理的线程,因此不会发生串行队列的那些问题(过多使用多线程,降低系统的响应性能)
// 自定义并行队列,将任务1234567加到串行队列中
dispatch_queue_t customConcurrentQueue = dispatch_queue_create("test.wangdachui.MyCustomQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk0");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk1");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk2");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk3");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk4");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk5");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
dispatch_async(customConcurrentQueue, ^{
NSLog(@"blk6");
NSLog(@"当前线程:%@",[NSThread currentThread]);
});
2.2.2 Dispatch Group:在使用Concurrent Dispatch Queue或同时使用多个Dispatch Queue时,想要在Dispatch Queue中的处理全部结束后再执行其他处理。可以使用Dispatch Group。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
// 把 queue 加入到 group
dispatch_group_async(group, queue, ^{
// 一些异步操作任务
sleep();
NSLog(@"任务GroupA\n当前线程:%@",[NSThread currentThread]);
});
// code 你可以在这里写代码做一些不必等待 group 内任务的操作
NSLog(@"任务GroupB\n当前线程:%@",[NSThread currentThread]);
// 当你在 group 的任务没有完成的情况下不能做更多的事时,阻塞当前线程等待 group 完工
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"任务GroupC\n当前线程:%@",[NSThread currentThread]);
dispatch_group_notify(group, dispatch_get_main_queue(), ^(){
// 从主线程上执行 UI 界面更新
NSLog(@"任务GroupD\n当前线程:%@",[NSThread currentThread]);
});
2.2.3 dispatch_barrier_async:
在访问数据库或文件时,为了高效地进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在任一读取处理没有执行的状态下,追加到Serial Dispatch Queue中即可(在写入处理结束之前,读取处理不可执行)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_async(queue, ^{
NSLog(@"blk0_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk1_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_for_writing");
});
dispatch_async(queue, ^{
NSLog(@"blk3_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_for_reading");
});
/*如上,如果简单地在dispatch_async函数中加入写入处理,那么根据Concurrent Dispatch Queue的性质,就有可能在追加到写入处理前面的处理中读取到与期待不符的数据,还可能因非法访问导致应用程序异常结束。因此我们要使用dispatch_barrier_async函数。dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue上的并行执行的处理全部结束之后,再将指定的处理追加到该Concurrent Dispatch Queue中。然后在由dispatch_barrier_async函数追加的处理执行完毕后,Concurrent Dispatch Queue才恢复为一般的动作,追加到该Concurrent Dispatch Queue的处理又开始执行。*/
dispatch_async(queue, ^{
NSLog(@"blk0_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk1_for_reading");
});
dispatch_barrier_async(queue, ^{
NSLog(@"blk2_for_writing");
});
dispatch_async(queue, ^{
NSLog(@"blk3_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk4_for_reading");
});
2.2.4 Dispatch Semaphore:信号量,关于信号量可以看我另外一篇帖子:iOS 信号量
// 创建信号量,并且设置值为10
dispatch_semaphore_t semaphore = dispatch_semaphore_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
for (int i = ; i < ; i++)
{ // 由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,从而semaphore-1.当循环10次后,semaphore等于0,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal 才会继续执行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(queue, ^{
NSLog(@"信号量-index=%i",i);
NSLog(@"信号量当前线程:%@",[NSThread currentThread]);
sleep();
// 每次发送信号则semaphore会+1,
dispatch_semaphore_signal(semaphore);
});
}
2.2.5 dispatch_apply:该函数按指定的次数将指定的Block追加到指定的Queue中,并等待全部处理执行结束
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_apply(, queue, ^(size_t index) {
NSLog(@"%zu",index);
});
NSLog(@"done");
/*打印结果
2017-09-20 10:49:29.760594+0800 Multithreading[11622:459025] 2
2017-09-20 10:49:29.760594+0800 Multithreading[11622:458947] 3
2017-09-20 10:49:29.760594+0800 Multithreading[11622:459027] 0
2017-09-20 10:49:29.760594+0800 Multithreading[11622:459026] 1
2017-09-20 10:49:29.760609+0800 Multithreading[11622:459077] 4
2017-09-20 10:49:29.760634+0800 Multithreading[11622:459078] 5
2017-09-20 10:49:29.760650+0800 Multithreading[11622:459079] 6
2017-09-20 10:49:29.760653+0800 Multithreading[11622:459080] 7
2017-09-20 10:49:29.760737+0800 Multithreading[11622:458947] 8
2017-09-20 10:49:29.760738+0800 Multithreading[11622:459025] 9
2017-09-20 10:49:29.761195+0800 Multithreading[11622:458947] done
*/
2.3 关于同步异步,串行并行的思考,看看打印结果,你就能悟真谛了。看的时候可以把测试代码拷贝到自己的项目中,自己思考一下,再回头看看打印结果。这样效果更好。大家不要嫌我写的烦,要好好听课。
//关于同步异步,串行,并行的思考
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_queue_t serialQueue = dispatch_queue_create("test.Lision.MyCustomQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrentQueue = dispatch_queue_create("test.Lision.MyCustomQueue", DISPATCH_QUEUE_CONCURRENT); [self dispatchAsyncWith:mainQueue];
/* 打印结果
2017-09-20 19:25:40.815678+0800 Multithreading[34153:2558588] 任务C
当前线程:<NSThread: 0x604000077440>{number = 1, name = main}
2017-09-20 19:25:42.843920+0800 Multithreading[34153:2558588] 任务A
当前线程:<NSThread: 0x604000077440>{number = 1, name = main}
2017-09-20 19:25:44.845176+0800 Multithreading[34153:2558588] 任务B
当前线程:<NSThread: 0x604000077440>{number = 1, name = main}
*/ //[self dispatchAsyncWith:globalQueue];
/* 打印结果:A/B的顺序随机
2017-09-20 19:28:26.395395+0800 Multithreading[34347:2580292] 任务C
当前线程:<NSThread: 0x60400006dc80>{number = 1, name = main}
2017-09-20 19:28:28.397384+0800 Multithreading[34347:2580443] 任务B
当前线程:<NSThread: 0x604000275ac0>{number = 3, name = (null)}
2017-09-20 19:28:28.397384+0800 Multithreading[34347:2580446] 任务A
当前线程:<NSThread: 0x60c00007c680>{number = 4, name = (null)}
*/ //[self dispatchAsyncWith:serialQueue];
/* 打印结果:串行队列生成一个新线程,AB顺序执行
2017-09-20 19:29:45.542392+0800 Multithreading[34394:2585219] 任务C
当前线程:<NSThread: 0x60000007f880>{number = 1, name = main}
2017-09-20 19:29:47.547666+0800 Multithreading[34394:2585681] 任务A
当前线程:<NSThread: 0x604000277540>{number = 3, name = (null)}
2017-09-20 19:29:49.550736+0800 Multithreading[34394:2585681] 任务B
当前线程:<NSThread: 0x604000277540>{number = 3, name = (null)}
*/ //[self dispatchAsyncWith:concurrentQueue];
/* 打印结果 A/B的顺序随机,AB并行执行,生成两个线程,最多生成几个线程由系统决定
2017-09-20 19:30:56.998360+0800 Multithreading[34446:2593417] 任务C
当前线程:<NSThread: 0x60400006ba40>{number = 1, name = main}
2017-09-20 19:30:59.001208+0800 Multithreading[34446:2593777] 任务B
当前线程:<NSThread: 0x608000275ac0>{number = 3, name = (null)}
2017-09-20 19:30:59.001206+0800 Multithreading[34446:2593775] 任务A
当前线程:<NSThread: 0x60400007ae40>{number = 4, name = (null)}
*/ //[self dispatchSyncWith:mainQueue];//死锁
/*
死锁原因:我们要在主线程同步执行任务A,但是同步执行任务A也算一个任务,我们称呼它为W。mainQueue是顺序执行的,当前正在执行的任务是W,W的内容是要执行A,所以把A加到mainQueue的尾部等待执行。A要执行,必须等W完成,W要完成,必须要执行A,相互等待,进入死锁。
所以,同步的时候,不能将任务添加到当前线程的串行Queue中
*/
//[self dispatchSyncWith:globalQueue];
/* 打印结果 同步阻塞,顺序执行ABC
2017-09-20 19:59:25.961727+0800 Multithreading[34773:2655128] 任务A
当前线程:<NSThread: 0x60c000261bc0>{number = 1, name = main}
2017-09-20 19:59:27.962571+0800 Multithreading[34773:2655128] 任务B
当前线程:<NSThread: 0x60c000261bc0>{number = 1, name = main}
2017-09-20 19:59:27.962824+0800 Multithreading[34773:2655128] 任务C
当前线程:<NSThread: 0x60c000261bc0>{number = 1, name = main}
*/
// [self dispatchSyncWith:serialQueue];
/*
自己猜
*/
// [self dispatchSyncWith:concurrentQueue];
/*
自己猜
*/
} //异步调用各种Queue
- (void)dispatchAsyncWith:(dispatch_queue_t)queue {
dispatch_async(queue, ^{
sleep();
NSLog(@"任务A\n当前线程:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep();
NSLog(@"任务B\n当前线程:%@",[NSThread currentThread]);
});
NSLog(@"任务C\n当前线程:%@",[NSThread currentThread]);
} //同步调用各种Queue
- (void)dispatchSyncWith:(dispatch_queue_t)queue {
dispatch_sync(queue, ^{
sleep();
NSLog(@"任务A\n当前线程:%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
sleep();
NSLog(@"任务B\n当前线程:%@",[NSThread currentThread]);
});
NSLog(@"任务C\n当前线程:%@",[NSThread currentThread]);
}
留了两个没有给结果,很简单的,经过上面的学习,结果是不是很简单。帖子准备了好几天,查阅了很多资料。关于使用NSOperation进行多线程编程,看我这篇帖子:iOS多线程--NSOperation
iOS多线程编程的更多相关文章
- iOS多线程编程指南
iOS多线程编程指南(拓展篇)(1) 一.Cocoa 在Cocoa上面使用多线程的指南包括以下这些: (1)不可改变的对象一般是线程安全的.一旦你创建了它们,你可以把这些对象在线程间安全的传递.另一方 ...
- iOS多线程编程原理及实践
摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...
- IOS高级编程之三:IOS 多线程编程
多线程的概念在各个操作系统上都会接触到,windows.Linux.mac os等等这些常用的操作系统,都支持多线程的概念. 当然ios中也不例外,但是线程的运行节点可能是我们平常不太注意的. 例如: ...
- iOS多线程编程Part 1/3 - NSThread & Run Loop
前言 多线程的价值无需赘述,对于App性能和用户体验都有着至关重要的意义,在iOS开发中,Apple提供了不同的技术支持多线程编程,除了跨平台的pthread之外,还提供了NSThread.NSOpe ...
- iOS多线程编程指南(一)关于多线程编程(转)
原文:http://www.dreamingwish.com/article/ios-multi-threaded-programming-a-multi-threaded-programming.h ...
- iOS多线程编程技术之NSThread、Cocoa NSOperation、GCD
原文出处: 容芳志的博客 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Central Dispatch) 这 ...
- iOS多线程编程(四)------ GCD(Grand Central Dispatch)
一.简单介绍 是基于C语言开发的一套多线程开发机制.也是眼下苹果官方推荐的多线程开发方法.用起来也最简单.仅仅是它基于C语言开发,并不像NSOperation是面向对象的开发.而是全然面向过程的.假设 ...
- iOS多线程编程的知识梳理
多线程编程也称之为并发编程,由于其作用大,有比较多的理论知识,因此在面试中也是受到面试官的青睐.在日常项目开发中,至少网络请求上是需要使用到多线程知识的,虽然使用第三方的框架比如AFNetworkin ...
- iOS多线程编程Part 2/3 - NSOperation
多线程编程Part 1介绍了NSThread以及NSRunLoop,这篇Blog介绍另一种并发编程技术:NSOPeration. NSOperation & NSOperationQueue ...
随机推荐
- CentOS7 搭建Git服务器(转)
1.在服务器上创建一个新用户 adduser git 2.创建一个Git仓库 cd /data/git //切换到希望创建工作区的目录git init --bare sample.git //创建一个 ...
- Python3 TA-Lib
This is a Python wrapper for TA-LIB based on Cython instead of SWIG. From the homepage: TA-Lib is wi ...
- JDBC的链接及封装
导入 mysql 的jar包 jar包:可以直接拿来用,又不想我们看到源代码 sql语句 一定注意:当update,delete时 一定注意where 条件,一定要写!!! public stat ...
- 面试技巧,如何通过索引说数据库优化能力,内容来自Java web轻量级开发面试教程
上星期写了一个篇文章,数据库方面的面试技巧,如何从建表方面展示自己能力,承蒙管理员抬举,放入首页,也承蒙各位厚爱,两天内收获了将近770个点击,也一度进入48小时热榜. 为了感谢管理员和大家的支持,再 ...
- startsWith和endWith方法
startsWith(): 例如:if(a.startsWith(b)) //判断字符串a 是不是以字符串b开头. 语法1 public boolean startsWith(String prefi ...
- 3.修改第一个程序来点亮LED
在上一节中已经将驱动程序框架搭建好了 接下来开始写硬件的操作(控制LED): (1)看原理图,确定引脚 (2)看2440手册 (3)写代码(需要使用ioremap()函数映射虚拟地址,在linux中只 ...
- JS跨域请求 JSONP B/S全代码
Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准:Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有 ...
- 【★】Web精彩实战之
JS精彩实战之<智能迷宫> ---宝贵编程经验分享会--- hello大家好,这里是Web云课堂,之前的一年里我们经历了Html和CSS的系统攻城,此时的你们已经是做静态(动静结 ...
- 非对话框程序创建组合框Groupbox
对话框程序中的控件,例如button.groupbox之类,是直接放上去的.当然,除groupbox以外,在MFC中其他控件都有相对应的类,以支持程序员在非对话框程序中动态创建控件.而唯独好像没有gr ...
- 5th-个人总结(Alpha阶段)
一. 总结自己的Alpha过程 1.团队的整体情况 在团队中这次担任队长的职务. alpha阶段完成情况还算理想,大家都完成了指定的任务.但是也少不了犯错,一些需求没有划分的足够细致,后来功能完成后发 ...