Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
GCD方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。
GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。
GCD和block的配合使用,可以方便地进行多线程编程。
设计:GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行
队列dispatch queue分为下面三种:
1、用户队列Serial:又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。用函数 dispatch_queue_create创建的队列。
2、全局队列Global queues:又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
3、主线程队列Main dispatch queue:它是全局可用的serial queue,它是在应用程序主线程上执行任务的,且是串行的。可以调用dispatch_get_main_queue()来获得。
1、队列(1)全局队列
(1-1)主线程 dispatch_queue_t queue = dispatch_get_main_queue();
(1-2)子线程 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
(2)自定义队列
(2-1)串行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);
(2-2)并行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);
2、任务
(1)同步 dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
(2)异步 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
3、dispatch_once 只执行一次
4、dispatch_after 延迟执行
5、dispatch_group 任务组操作
6、dispatch_barrier 分段操作
自定义并行队列时,在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
7、dispatch_semaphore 信号量
GCD是多线程的一种。
既有同步方法,也有异步方法,如下所示:
(1)同步:同步执行-会阻塞进程,造成应用卡顿
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self showCount:@(1)];
});
(2)异步:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self showCount:@(1)];
});
GCD的有多种方式,代码示例:
- (void)showCount:(NSNumber *)number
{
NSInteger count = arc4random() % 10;
count = 10;
for (int i = 0; i < count; i++)
{
NSLog(@"第 %@ 个 i = %@", number, @(i));
// 休眠n秒再执行
[NSThread sleepForTimeInterval:0.2];
}
}
- (void)downloadImage:(NSString *)imageUrl
{
NSURL *url = [NSURL URLWithString:imageUrl];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
if (image == nil)
{
}
else
{
// 下载成功后 反回主线程处理
dispatch_async(dispatch_get_main_queue(), ^{
[self updateImage:image];
});
}
}
- (void)updateImage:(UIImage *)image
{
self.imageview.image = image;
}
// 同步执行-会阻塞进程,造成应用卡顿
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self showCount:@(1)];
});
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self showCount:@(2)];
});
// 子线程异步
- (void)runAsynchronizationGrobal
{
NSLog(@"---start---");
// 获取子队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 使用异步函数封装三个任务
dispatch_async(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.2]; // 模拟运行时间
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.2]; // 模拟运行时间
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
NSLog(@"---end---");
}
// 主线程同步(死锁)
- (void)runSynchronizationMain
{
NSLog(@"---start---");
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 使用同步函数封装三个任务
dispatch_sync(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
dispatch_sync(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
dispatch_sync(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
NSLog(@"---end---");
}
// 主线程异步,在主线程中先顺序执行完当前任务,再顺序执行主线程中其他线程任务
- (void)runAsynchronizationMain
{
NSLog(@"---start---");
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 使用异步函数封装三个任务
dispatch_async(queue, ^{
NSLog(@"任务1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0]; // 模拟运行时间
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 模拟运行时间
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.3]; // 模拟运行时间
});
NSLog(@"---end---");
}
// 只执行一次,在主线程中执行
- (void)runOnce
{
NSLog(@"---start---");
static dispatch_once_t once;
dispatch_once(&once, ^{
NSLog(@"任务one---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
NSLog(@"---end---");
}
// 延迟执行,自定义执行队列
- (void)runAfter
{
NSLog(@"---start---");
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_after(time, queue, ^{
NSLog(@"任务 after---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; // 模拟运行时间
});
NSLog(@"---end---");
}
// 自定义dispatch_queue_t(如要要自定义queue,可以用dispatch_queue_create方法)
dispatch_queue_t urls_queue = dispatch_queue_create("http://blog.csdn.net/potato512", NULL);
dispatch_async(urls_queue, ^{
// your code
[self showCount:@(4)];
});
// 分组执行,自定义执行队列(主线程时,顺序执行)
- (void)runGroup
{
NSLog(@"---start---");
dispatch_group_t group = dispatch_group_create();
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_group_async(group, queue, ^{
NSLog(@"任务 1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.3]; // 模拟运行时间
});
dispatch_group_async(group, queue, ^{
NSLog(@"任务 2---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 模拟运行时间
});
// 1
// dispatch_group_notify(group, queue, ^{
// NSLog(@"任务 汇总---%@", [NSThread currentThread]);
// [NSThread sleepForTimeInterval:0.5]; // 模拟运行时间
// });
// 或2
dispatch_group_enter(group);
NSLog(@"任务 汇总---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5]; // 模拟运行时间
dispatch_group_leave(group);
dispatch_group_async(group, queue, ^{
NSLog(@"任务 3---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 模拟运行时间
});
// 或3(避免在主线程使用,造成主线程阻塞)
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// dispatch_group_async(group, queue, ^{
// NSLog(@"任务 3---%@", [NSThread currentThread]);
// [NSThread sleepForTimeInterval:1.0]; // 模拟运行时间
// });
NSLog(@"---end---");
}
// 自定义并行队列时,在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
- (void)runBarrier
{
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_queue_t queue = dispatch_queue_create("001", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任务 1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5]; // 模拟运行时间
});
dispatch_async(queue, ^{
NSLog(@"任务 2---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.2]; // 模拟运行时间
});
dispatch_barrier_async(queue, ^{
NSLog(@"任务 3---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0]; // 模拟运行时间
});
for (int i = 0; i < 3; i++)
{
dispatch_async(queue, ^{
NSLog(@"任务 %d---%@", (i + 4), [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.2]; // 模拟运行时间
});
}
}
// 信息量
- (void)runSemaphore
{
dispatch_queue_t workConcurrentQueue = dispatch_queue_create("cccccccc", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t serialQueue = dispatch_queue_create("sssssssss", DISPATCH_QUEUE_SERIAL);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
for (NSInteger i = 0; i < 10; i++)
{
dispatch_async(serialQueue, ^{
dispatch_async(workConcurrentQueue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"thread-info:%@开始执行任务%d", [NSThread currentThread], (int)i);
sleep(1);
NSLog(@"thread-info:%@结束执行任务%d", [NSThread currentThread], (int)i);
NSLog(@"---");
dispatch_semaphore_signal(semaphore);
});
});
}
NSLog(@"主线程...!");
}
注意:
(1)开始执行后没有停止方法(慎重使用)
(2)主线程中使用同步会造成死锁
效果图