iOS-多线程编程学习之GCD——串行队列和并发队列(五)
2016-02-27 09:51
471 查看
Grand Central Dispatch(GCD)有很多部分构成,例如有很好的语言特性,运行库,还提供了系统的、高效的方式来支持具有多核处理器的iOS和OS X设备进行并发事件处理。
BSD子系统,CoreFoundation和Cocoa APIs都已经使用这个增强特性来进行扩展了,因为它可以使得你的系统和应用运行的更快,更有效率,响应更及时。GCD是运行在系统级别的,他可以更好的满足应用运行时的需求,更合理调度有限的系统资源。
GCD并不是被限制只能在系统级别应用上使用的,我们可以在更高层的应用上也使用它。但是一般情况下我们还可以考虑Cocoa中是否有类似的对象可以实现相似的功能,例如NSOperation,它也提供了很简单便捷的方式来进行并发任务处理【传送门——iOS-多线程编程学习之NSOperation(四)】。
并发队列:允许多个任务同时执行。
串行队列:任务按顺序依次执行。
系统默认有一个和主线程绑定的串行队列,还有一个全局的并发队列。这两个队列都可以通过响应的方法来获得。
DISPATCH_QUEUE_PRIORITY_HIGH 2,优先级高
DISPATCH_QUEUE_PRIORITY_DEFAULT 0,默认优先级,中
DISPATCH_QUEUE_PRIORITY_LOW -2,优先级低
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN,后台模式,优先级最低
代码也很简单。
同步,其会在当前线程立即执行添加的任务(无论是串行还是并行队列都如此)。
异步,其会新创建一个新的线程来执行任务。而异步对于串行和并行队列的又不一样的意义的。
对于异步执行的串行队列的话,新添加的多个任务会在新创建的线程中依次执行,即一个执行完在执行另一个任务,有点类似同步执行的样子(其区别可以看做是同步不会创建新的线程,而异步会创建新的线程,且只创建一个)。我们可以看一下例子。
然后我们看一下输出结果。我们会发现使用同步方式执行的任务都会被立即执行,并且是在当前线程(主线程)中执行的。而用异步方式的任务则会在新创建的线程(number=2)中执行,并且它们是按照一定顺序执行的(串行01->串行02->串行03)。
我们再来看看如果是并发队列的话,使用同步方式执行任何则和串行队列一样。而使用异步方式执行任务的话,新添加的任务都会放到新创建的线程,即每个任务在单独线程中,并且所有的任务都是并发执行的,而不像串行队列是有顺序的。如果是异步方式执行的话,则每个任务都会新开一个线程,并且这些任务是并发执行的。我们来看一下下面这个例子。
然后我们来看一下输出结果。这刚好验证了我们的说法。
GCD实践——串行队列/并发队列与iOS多线程详解
iOS开发–四种多线程技术方案
BSD子系统,CoreFoundation和Cocoa APIs都已经使用这个增强特性来进行扩展了,因为它可以使得你的系统和应用运行的更快,更有效率,响应更及时。GCD是运行在系统级别的,他可以更好的满足应用运行时的需求,更合理调度有限的系统资源。
GCD并不是被限制只能在系统级别应用上使用的,我们可以在更高层的应用上也使用它。但是一般情况下我们还可以考虑Cocoa中是否有类似的对象可以实现相似的功能,例如NSOperation,它也提供了很简单便捷的方式来进行并发任务处理【传送门——iOS-多线程编程学习之NSOperation(四)】。
一、GCD与ARC
当使用Objective-C来构建应用时,所有的
dispatch obeject都是
Objective-C类型的对象。所以当在应用中开启了ARC(自动引用计数)时,这些
dispatch obeject也会想OC的对象一样被自动的发送
retain和
release消息。当ARC被禁用时(也就是进行MRC手动内存管理时),可以通过使用
dispatch_retain和
dispatch_release来实现类似OC对象的retain和release操作。
二、创建任务队列
GCD中的队列主要分两种。并发队列:允许多个任务同时执行。
串行队列:任务按顺序依次执行。
系统默认有一个和主线程绑定的串行队列,还有一个全局的并发队列。这两个队列都可以通过响应的方法来获得。
2.1 获得主线程的串行队列
调用这个方法获取主线程队列时,该队列是由主线程来自动创建的。dispatch_queue_t mainQueue = dispatch_get_main_queue();
2.2 获得全局的并发队列
获取全局并发队列的方法中有两个参数,第二个参数暂时没有使用,默认传值0就好。第一个参数表示队列的优先级,其中优先级主要分为4种。DISPATCH_QUEUE_PRIORITY_HIGH 2,优先级高
DISPATCH_QUEUE_PRIORITY_DEFAULT 0,默认优先级,中
DISPATCH_QUEUE_PRIORITY_LOW -2,优先级低
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN,后台模式,优先级最低
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2.3 创建自定义的队列
创建自定义的队列主要有两种,一种是串行队列,一种是并行队列。在创建自定义队列时会需要传两个参数,第一个为队列的名称,第二个为表示队列类型的常量(串行还是并行)。DISPATCH_QUEUE_SERIAL //串行队列 DISPATCH_QUEUE_CONCURRENT //并行队列
代码也很简单。
//串行队列 dispatch_queue_t serialQueue = dispatch_queue_create("com.lysongzi.serial", DISPATCH_QUEUE_SERIAL); //并行队列 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lysongzi.concurrent", DISPATCH_QUEUE_CONCURRENT);
三、同步和异步
当我们创建了队列之后,我们需要把任务添加到队列中,并指定以同步还是异步的方式执行添加到队列中的任务。同步,其会在当前线程立即执行添加的任务(无论是串行还是并行队列都如此)。
异步,其会新创建一个新的线程来执行任务。而异步对于串行和并行队列的又不一样的意义的。
对于异步执行的串行队列的话,新添加的多个任务会在新创建的线程中依次执行,即一个执行完在执行另一个任务,有点类似同步执行的样子(其区别可以看做是同步不会创建新的线程,而异步会创建新的线程,且只创建一个)。我们可以看一下例子。
-(void)testSerialQueue { //创建串行队列,传入参数为DISPATCH_QUEUE_SERIAL self.serialQueue = dispatch_queue_create("com.lysongzi.serial", DISPATCH_QUEUE_SERIAL); //同步执行队列中的任务,会立即在当前线程执行该任务 dispatch_sync(self.serialQueue, ^{ NSLog(@"这里是同步执行的串行队列01。===> %@", [NSThread currentThread]); }); //异步执行任务,会新开一个线程,多个任务按顺序执行 dispatch_async(self.serialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"串行01 ===> %d ===> %@", i, [NSThread currentThread]); } }); dispatch_sync(self.serialQueue, ^{ NSLog(@"这里是同步执行的串行队列02。===> %@", [NSThread currentThread]); }); dispatch_async(self.serialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"串行02 ===> %d ===> %@", i, [NSThread currentThread]); } }); dispatch_async(self.serialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"串行03 ===> %d ===> %@", i, [NSThread currentThread]); } }); }
然后我们看一下输出结果。我们会发现使用同步方式执行的任务都会被立即执行,并且是在当前线程(主线程)中执行的。而用异步方式的任务则会在新创建的线程(number=2)中执行,并且它们是按照一定顺序执行的(串行01->串行02->串行03)。
2016-02-26 22:17:34.745 GCDDemon[4084:422492] 这里是同步执行的串行队列01。===> <NSThread: 0x100103080>{number = 1, name = main} 2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 0 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 1 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 2 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422492] 这里是同步执行的串行队列02。===> <NSThread: 0x100103080>{number = 1, name = main} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 0 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 1 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 2 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 0 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 1 ===> <NSThread: 0x100103a70>{number = 2, name = (null)} 2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 2 ===> <NSThread: 0x100103a70>{number = 2, name = (null)}
我们再来看看如果是并发队列的话,使用同步方式执行任何则和串行队列一样。而使用异步方式执行任务的话,新添加的任务都会放到新创建的线程,即每个任务在单独线程中,并且所有的任务都是并发执行的,而不像串行队列是有顺序的。如果是异步方式执行的话,则每个任务都会新开一个线程,并且这些任务是并发执行的。我们来看一下下面这个例子。
-(void)testConcurrentQueue { //创建并发队列,传入参数为DISPATCH_QUEUE_CONCURRENT self.concurrentQueue = dispatch_queue_create("com.lysongzi.concurrent", DISPATCH_QUEUE_CONCURRENT); //同步执行队列中的任务,会立即执行该任务 dispatch_sync(self.concurrentQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"并发同步01 ===> %d ===> %@", i, [NSThread currentThread]); } }); dispatch_sync(self.concurrentQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"并发同步02 ===> %d ===> %@", i, [NSThread currentThread]); } }); //异步执行并发队列 dispatch_async(self.concurrentQueue, ^{ for (int i = 0; i < 5; i++) { NSLog(@"并发异步01 ===> %d ===> %@", i, [NSThread currentThread]); } }); dispatch_async(self.concurrentQueue, ^{ for (int i = 0; i < 5; i++) { NSLog(@"并发异步02 ===> %d ===> %@", i, [NSThread currentThread]); } }); dispatch_async(self.concurrentQueue, ^{ for (int i = 0; i < 5; i++) { NSLog(@"并发异步03 ===> %d ===> %@", i, [NSThread currentThread]); } }); }
然后我们来看一下输出结果。这刚好验证了我们的说法。
2016-02-26 22:43:17.553 GCDDemon[4223:436777] 并发同步01 ===> 0 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步01 ===> 1 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步01 ===> 2 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 0 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 1 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 2 ===> <NSThread: 0x100108c80>{number = 1, name = main} 2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 0 ===> <NSThread: 0x100700110>{number = 3, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 1 ===> <NSThread: 0x100700110>{number = 3, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 0 ===> <NSThread: 0x1002000a0>{number = 2, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 2 ===> <NSThread: 0x100700110>{number = 3, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 1 ===> <NSThread: 0x1002000a0>{number = 2, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 3 ===> <NSThread: 0x100700110>{number = 3, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 2 ===> <NSThread: 0x1002000a0>{number = 2, name = (null)} 2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 4 ===> <NSThread: 0x100700110>{number = 3, name = (null)} 2016-02-26 22:43:17.556 GCDDemon[4223:436824] 并发异步01 ===> 0 ===> <NSThread: 0x10010aec0>{number = 4, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436825] 并发异步02 ===> 3 ===> <NSThread: 0x1002000a0>{number = 2, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 1 ===> <NSThread: 0x10010aec0>{number = 4, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436825] 并发异步02 ===> 4 ===> <NSThread: 0x1002000a0>{number = 2, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 2 ===> <NSThread: 0x10010aec0>{number = 4, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 3 ===> <NSThread: 0x10010aec0>{number = 4, name = (null)} 2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 4 ===> <NSThread: 0x10010aec0>{number = 4, name = (null)}
源代码
Github-GCDDemon参考资料
苹果官方文档-Grand Central Dispatch (GCD) ReferenceGCD实践——串行队列/并发队列与iOS多线程详解
iOS开发–四种多线程技术方案
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- 肯特·贝克:改变人生的代码整理魔法
- 你应该学习哪种编程语言?
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- [转]我们需要一种其他人能使用的编程语言
- DB2编程序技巧(1)
- DB2编程序技巧 (四)
- 女人VS编程_国庆快乐
- DB2编程序技巧 (六)
- DB2编程序技巧 (三)
- DB2编程序技巧 (九)
- DB2编程序技巧 (七)
- DB2编程序小小技巧
- DB2编程序技巧 (五)