GCD,全名是 Grand Central Dispatch ,通常是 create 一个 dispatch_queue_t
队列,然后把任务放到队列中,队列分为 dispatch_async
(异步队列)和 dispatch_sync
(同步队列)。
- 串行队列
- 并行队列
- 全局队列
- 主线程队列
- 实际操作一(网络下载图片)
- 实际操作二(iOS 推送并发执行)
简单地理解
- GCD 的基本思想是就将操作放在队列中去执行
- 操作使用 Block 定义
- 队列负责调度任务执行所在的线程以及具体的执行时间
- 队列的特点是先进先出(FIFO)的,新添加至对列的操作都会排在队尾
- GCD 的函数都是以 dispatch 开头的
串行队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| - (void)gcdDemo1 {
// 串行队列 dispatch_queue_t q = dispatch_queue_create("com.pupboss.gcddemo1", DISPATCH_QUEUE_SERIAL)
// 串行行队列的同步任务,同样会在主线程上运行 for (int i = 0 // 同步任务顺序执行 dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i) }) }
for (int i = 0 // 异步任务,并发执行,但是如果在串行队列中,仍然会依次顺序执行 dispatch_async(q, ^{ // [NSThread currentThread] 可以在开发中,跟踪当前线程 // num = 1,表示主线程 // num = 2,表示第2个子线程。。。 NSLog(@"%@ %d", [NSThread currentThread], i) }) } }
2015-05-23 22:03:17.990 Multi-Thread-Test[4502:211585] <NSThread: 0x7feeb3f289d0>{number = 1, name = main} 0 2015-05-23 22:03:17.990 Multi-Thread-Test[4502:211585] <NSThread: 0x7feeb3f289d0>{number = 1, name = main} 1 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211585] <NSThread: 0x7feeb3f289d0>{number = 1, name = main} 2 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211585] <NSThread: 0x7feeb3f289d0>{number = 1, name = main} 3 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211585] <NSThread: 0x7feeb3f289d0>{number = 1, name = main} 4 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211685] <NSThread: 0x7feeb506dc70>{number = 2, name = (null)} 0 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211685] <NSThread: 0x7feeb506dc70>{number = 2, name = (null)} 1 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211685] <NSThread: 0x7feeb506dc70>{number = 2, name = (null)} 2 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211685] <NSThread: 0x7feeb506dc70>{number = 2, name = (null)} 3 2015-05-23 22:03:17.991 Multi-Thread-Test[4502:211685] <NSThread: 0x7feeb506dc70>{number = 2, name = (null)} 4
|
并行队列
这个比较有意思了,看下面这种情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| - (void)gcdDemo2 { dispatch_queue_t q = dispatch_queue_create("com.pupboss.gcddemo2", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 5; ++i) { dispatch_async(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
for (int i = 0; i < 5; ++i) { dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); } }
|
执行结果是下面的,非常混乱,是吧,但是
1 2 3 4 5 6 7 8 9 10
| 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212722] <NSThread: 0x7f98e9600000>{number = 5, name = (null)} 3 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212715] <NSThread: 0x7f98e9979e90>{number = 2, name = (null)} 0 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212664] <NSThread: 0x7f98e9428a30>{number = 1, name = main} 0 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212714] <NSThread: 0x7f98e9a00a70>{number = 4, name = (null)} 1 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212716] <NSThread: 0x7f98e98301d0>{number = 3, name = (null)} 2 2015-05-23 22:04:03.804 Multi-Thread-Test[4527:212723] <NSThread: 0x7f98e9a003b0>{number = 6, name = (null)} 4 2015-05-23 22:04:03.805 Multi-Thread-Test[4527:212664] <NSThread: 0x7f98e9428a30>{number = 1, name = main} 1 2015-05-23 22:04:03.805 Multi-Thread-Test[4527:212664] <NSThread: 0x7f98e9428a30>{number = 1, name = main} 2 2015-05-23 22:04:03.805 Multi-Thread-Test[4527:212664] <NSThread: 0x7f98e9428a30>{number = 1, name = main} 3 2015-05-23 22:04:03.805 Multi-Thread-Test[4527:212664] <NSThread: 0x7f98e9428a30>{number = 1, name = main} 4
|
如果把两个任务换换位置,变成这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| for (int i = 0; i < 5; ++i) { dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
for (int i = 0; i < 5; ++i) { dispatch_async(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
|
运行结果就变了
1 2 3 4 5 6 7 8 9 10
| 2015-05-23 22:04:58.874 Multi-Thread-Test[4555:214018] <NSThread: 0x7fc8d3c28bd0>{number = 1, name = main} 0 2015-05-23 22:04:58.876 Multi-Thread-Test[4555:214018] <NSThread: 0x7fc8d3c28bd0>{number = 1, name = main} 1 2015-05-23 22:04:58.876 Multi-Thread-Test[4555:214018] <NSThread: 0x7fc8d3c28bd0>{number = 1, name = main} 2 2015-05-23 22:04:58.876 Multi-Thread-Test[4555:214018] <NSThread: 0x7fc8d3c28bd0>{number = 1, name = main} 3 2015-05-23 22:04:58.876 Multi-Thread-Test[4555:214018] <NSThread: 0x7fc8d3c28bd0>{number = 1, name = main} 4 2015-05-23 22:04:58.880 Multi-Thread-Test[4555:214043] <NSThread: 0x7fc8d3e00ae0>{number = 2, name = (null)} 0 2015-05-23 22:04:58.881 Multi-Thread-Test[4555:214043] <NSThread: 0x7fc8d3e00ae0>{number = 2, name = (null)} 1 2015-05-23 22:04:58.881 Multi-Thread-Test[4555:214044] <NSThread: 0x7fc8d3e03280>{number = 3, name = (null)} 2 2015-05-23 22:04:58.881 Multi-Thread-Test[4555:214043] <NSThread: 0x7fc8d3e00ae0>{number = 2, name = (null)} 4 2015-05-23 22:04:58.881 Multi-Thread-Test[4555:214046] <NSThread: 0x7fc8d3f0adb0>{number = 4, name = (null)} 3
|
说明并行队列中的同步任务,还是在主线程上,并且执行完了之后才会往下走
全局队列
苹果为了方便多线程的设计,提供一个全局队列,供所有的APP共同使用
1
| dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
两个参数,一个是优先级,一个是 0,现在只能写 0,因为苹果没想好这个参数怎么开放给开发者。
全局队列用起来跟并行队列是差不多的,所以就不上代码了
主线程队列
每一个应用程序都只有一个主线程,有些操作,需要放到主线程队列来完成,比如数据下载完,刷新界面,等等
主线程队列千万不要使用同步任务,会发生阻塞!
1 2 3 4 5 6 7 8 9 10 11
| - (void)gcdDemo4 {
dispatch_queue_t q = dispatch_get_main_queue();
for (int i = 0; i < 5; ++i) { dispatch_async(q, ^{ NSLog(@"%@ - %d", [NSThread currentThread], i); }); } }
|
运行结果
1 2 3 4 5
| 2015-05-23 22:34:17.663 Multi-Thread-Test[4800:243581] <NSThread: 0x7fbffc023060>{number = 1, name = main} - 0 2015-05-23 22:34:17.664 Multi-Thread-Test[4800:243581] <NSThread: 0x7fbffc023060>{number = 1, name = main} - 1 2015-05-23 22:34:17.664 Multi-Thread-Test[4800:243581] <NSThread: 0x7fbffc023060>{number = 1, name = main} - 2 2015-05-23 22:34:17.664 Multi-Thread-Test[4800:243581] <NSThread: 0x7fbffc023060>{number = 1, name = main} - 3 2015-05-23 22:34:17.664 Multi-Thread-Test[4800:243581] <NSThread: 0x7fbffc023060>{number = 1, name = main} - 4
|
批量下载图片
1 2 3 4 5 6 7 8 9 10 11 12
| for (int i = 1; i < 100; ++i) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i); NSString *imageName = [NSString stringWithFormat:@"%d.jpg", i];
NSString *url = [NSString stringWithFormat:@"http://xxxxy/%@", imageName];
[LJFileTool writeImageToFileName:imageName withImgURL:url]; }); }
|
这么写没什么好处 = =,也就是不阻塞主线程,除此之外真没啥了。。。。卧槽,本来想写成异步任务的,结果发现老是有问题,而且速度也一般。
iOS 的推送
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| NSArray *startArr = [NSArray arrayWithContentsOfFile:@"/xxxxx/test.plist"];
dispatch_queue_t q = dispatch_queue_create("com.pupboss.pusher", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < startArr.count; ++i) { dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
NSLog(@"%@", startArr[i]);
[self sendMsg:startArr[i]]; }); }
|