推荐:http://www.jianshu.com/p/0b0d9b1f1f19?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=qq
GCD:Grand Central Dispatch,它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。
主要由两个重要概念:任务 和 队列。
需要掌握怎么创建队列和创建任务。
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行 和 异步执行。
同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。
队列:用于存放任务。一共有两种队列, 串行队列 和 并行队列。
串行队列 :串行队列中的任务会根据队列的定义 FIFO 的执行,一个接一个的先进先出的进行执行。放到串行队列的任务,GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
并行队列 :放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。
分析一个常见的栗子来展开吧:
--栗子--
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString* result = [self fetchResultFromWebWithParameter:parameter];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithResult:parameter];
});
});
在栗子中:
dispatch_async(dispatch_sync)表示当前创建的任务是异步还是同步执行的(前面说了它们的区别主要在于会不会阻塞当前线程),也是通过它把相应的任务添加到的队列中去(一般都是在做dispatch_async异步的吧);
同步任务:会阻塞当前线程 (SYNC)
dispatch_sync(queue, ^{
//code here
});
异步任务:不会阻塞当前线程 (ASYNC)
dispatch_async(queue, ^{
//code here
});
-------------------------------------------------------------分割君-----------------------------------------------------------------
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 和 dispatch_get_main_queue()表示当前任务会被放在哪个队列里面,其中DISPATCH_QUEUE_PRIORITY_DEFAULT表示优先级,0 作为flag是保留字段备用(一般为0),
看看都有哪些队列了?
分为 Serial Dispatch Queue(串行队列)和Concurrent Dispatch Queue(并行队列)
Serial Dispatch Queue – 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
Concurrent Dispatch Queue – 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。
GCD的队列又分为:主队列(main_queue),全局队列(global_queue),用户创建队列(create)。
主队列(main_queue)和 全局队列global_queue是系统默认就有的(也就是说程序创建好就有了,只需要去获取他们然后使用就好,真棒):
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
dispatch_queue_t mainQ = dispatch_get_main_queue(); //它用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。
其中main_queue是串行队列,global_queue是并行队列;
对于全局队列(global_queue),默认有四个,分为四个优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
DISPATCH_QUEUE_PRIORITY_HIGH:优先级最高,在default,和low之前执行
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认优先级,在low之前,在high之后
DISPATCH_QUEUE_PRIORITY_LOW 在high和default后执行
DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到这个队列的任务会在high优先级的任务和已经提交到background队列的执行完后执行。
通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作,
除了系统的提供的队列,用户还可以自己创建自己的自定义队列:
dispatch_queue_t queue = dispatch_queue_create(“myQueue”, NULL);
使用还是一样的:
dispatch_async(queue, ^{
printf("Do some work here.\n");
});
dispatch_queue_t queue = dispatch_queue_create(“myQueue”, NULL);
上面这句代码中第一个参数(“myQueue”)是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空;第二个才是最重要的,第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。
也就是说,自己可以创建 串行队列, 也可以创建 并行队列,如下:
//串行队列
dispatch_queue_t queue = dispatch_queue_create("fk_Queue", NULL);
dispatch_queue_t queue = dispatch_queue_create("fk_Queue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("fk_Queue", DISPATCH_QUEUE_CONCURRENT);
-------------------------------------------------------------分割君-----------------------------------------------------------------
^{ //your code//}表示你要执行的任务内容,显然是block;
-------------------------------------------------------------分割君-----------------------------------------------------------------
最后来看看他们的执行方式:
————— | 同步执行 | 异步执行 |
---|---|---|
串行队列 | 当前线程,一个一个执行 | 其他线程(同一线程),一个一个执行 |
并行队列 | 当前线程,一个一个执行 | 开很多线程,一起执行 |
再举个栗子:
dispatch_queue_t queue;
queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); //并行队列
dispatch_sync(queue, ^{
sleep(3);
NSLog(@"first sync");
});
dispatch_sync(queue, ^{
NSLog(@"second sync");
});
或者
dispatch_queue_t queue2;
queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL); // 串行队列
dispatch_sync(queue2, ^{
NSLog(@"first sync");
});
dispatch_sync(queue, ^{
NSLog(@"second sync");
});
结果都是:
2015-10-08 18:09:14.007 FKTest[1724:221306] first sync
2015-10-08 18:09:14.008 FKTest[1724:221306] second sync
所以只要是dispatch_sync(同步执行)的就是意味着会阻塞当前线程,知道其任务完成(也就是说block执行结束),不管队列是串行的还是并行的;
而dispatch_async(异步执行)则会根据的队列进行相关的操作:
串行队列:按照FIFO,一次取一个任务,完了再取,所以还是one by one,但是在哪个线程执行则要取决于当前的queue了,如果是同一个串行queue,那么会在一个线程中执行,如果是在不同的串行queue中则会在不同的线程中执行;
测试代码1:
dispatch_queue_t queue;
queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"first sync--- %@",[NSThread currentThread]);
});
dispatch_queue_t queue2;
queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue2, ^{
NSLog(@"second sync--- %@",[NSThread currentThread]);
});
结果:
2015-10-08 18:46:59.822 FKTest[2087:257779] first sync--- <NSThread: 0x7fe77a08adb0>{number = 2, name = (null)}
2015-10-08 18:46:59.822 FKTest[2087:257778] second sync--- <NSThread: 0x7fe77a102ad0>{number = 3, name = (null)}
即在不同的线程执行的
测试代码2:
dispatch_queue_t queue;
queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"first sync--- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"second sync--- %@",[NSThread currentThread]);
});
结果:
2015-10-08 18:48:00.060 FKTest[2110:259038] first sync--- <NSThread: 0x7fd878705a70>{number = 2, name = (null)}
2015-10-08 18:48:00.060 FKTest[2110:259038] second sync--- <NSThread: 0x7fd878705a70>{number = 2, name = (null)}
即在同一个线程里执行的
并行队列:这个很显然了,异步的,还是并行的队列,相当于大家相互没什么关系,谁爱在哪个线程玩,什么时候玩都是自己的事,不管彼此。