Grand Central Dispatch(GCD)有很多部分构成,例如有很好的语言特性,运行库,还提供了系统的、高效的方式来支持具有多核处理器的iOS和OS X设备进行并发事件处理。
BSD子系统,CoreFoundation和Cocoa APIs都已经使用这个增强特性来进行扩展了,因为它可以使得你的系统和应用运行的更快,更有效率,响应更及时。GCD是运行在系统级别的,他可以更好的满足应用运行时的需求,更合理调度有限的系统资源。
GCD并不是被限制只能在系统级别应用上使用的,我们可以在更高层的应用上也使用它。但是一般情况下我们还可以考虑Cocoa中是否有类似的对象可以实现相似的功能,例如NSOperation,它也提供了很简单便捷的方式来进行并发任务处理【传送门——iOS-多线程编程学习之NSOperation(四)】。
当使用Objective-C
来构建应用时,所有的dispatch obeject
都是Objective-C
类型的对象。所以当在应用中开启了ARC(自动引用计数)时,这些dispatch obeject
也会想OC的对象一样被自动的发送retain
和release
消息。当ARC被禁用时(也就是进行MRC手动内存管理时),可以通过使用dispatch_retain
和dispatch_release
来实现类似OC对象的retain和release操作。
GCD中的队列主要分两种。
系统默认有一个和主线程绑定的串行队列,还有一个全局的并发队列。这两个队列都可以通过响应的方法来获得。
调用这个方法获取主线程队列时,该队列是由主线程来自动创建的。
dispatch_queue_t mainQueue = dispatch_get_main_queue();
获取全局并发队列的方法中有两个参数,第二个参数暂时没有使用,默认传值0就好。第一个参数表示队列的优先级,其中优先级主要分为4种。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
创建自定义的队列主要有两种,一种是串行队列,一种是并行队列。在创建自定义队列时会需要传两个参数,第一个为队列的名称,第二个为表示队列类型的常量(串行还是并行)。
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。===> {number = 1, name = main}
2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 0 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 1 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.747 GCDDemon[4084:422514] 串行01 ===> 2 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422492] 这里是同步执行的串行队列02。===> {number = 1, name = main}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 0 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 1 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行02 ===> 2 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 0 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 1 ===> {number = 2, name = (null)}
2016-02-26 22:17:34.748 GCDDemon[4084:422514] 串行03 ===> 2 ===> {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 ===> {number = 1, name = main}
2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步01 ===> 1 ===> {number = 1, name = main}
2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步01 ===> 2 ===> {number = 1, name = main}
2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 0 ===> {number = 1, name = main}
2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 1 ===> {number = 1, name = main}
2016-02-26 22:43:17.554 GCDDemon[4223:436777] 并发同步02 ===> 2 ===> {number = 1, name = main}
2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 0 ===> {number = 3, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 1 ===> {number = 3, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 0 ===> {number = 2, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 2 ===> {number = 3, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 1 ===> {number = 2, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 3 ===> {number = 3, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436825] 并发异步02 ===> 2 ===> {number = 2, name = (null)}
2016-02-26 22:43:17.555 GCDDemon[4223:436826] 并发异步03 ===> 4 ===> {number = 3, name = (null)}
2016-02-26 22:43:17.556 GCDDemon[4223:436824] 并发异步01 ===> 0 ===> {number = 4, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436825] 并发异步02 ===> 3 ===> {number = 2, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 1 ===> {number = 4, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436825] 并发异步02 ===> 4 ===> {number = 2, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 2 ===> {number = 4, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 3 ===> {number = 4, name = (null)}
2016-02-26 22:43:17.582 GCDDemon[4223:436824] 并发异步01 ===> 4 ===> {number = 4, name = (null)}
Github-GCDDemon