标签:需要 梳理 并发 thread 参数 pre ndt 效果 顺序
在此之前, GCD中还涉及到两个十分重要的概念, 就是任务和队列
dispatch_async(dispatch_queue_t _Nonnull queue, ^(void)block)
dispatch_sync(dispatch_queue_t _Nonnull queue, ^(void)block)
这个函数中需要填入两个参数, 一个是队列, 一个是任务, 任务就是封装在block代码块中的. 所以, 我们在使用以上两个函数时, 只需要创建队列, 以及把自己需要执行的代码封装在block中就可以了
CGD中还给我们提供了两个类似的函数, 请看
dispatch_sync_f(dispatch_queue_t queue,
void *_Nullable context,
dispatch_function_t work);
dispatch_async_f(dispatch_queue_t queue,
void *_Nullable context,
dispatch_function_t work);
这两个函数就没有之前那两个简单, 因为这两个函数不是将任务封装在block代码块中, 而是封装在函数里
如下面的代码所示
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
dispatch_async_f(dispatch_get_global_queue(0, 0), nil, task);
}
void task (void *param) {
NSLog(@"downloadTask-------%@",[NSThread currentThread]);
}
dispatch_async_f(_, _, _);
这个函数的三个参数我分别传入
在我定义的这个返回值为空, 参数为void*类型的函数中, 我把我需要操作的任务封装在里面, 其实里面的代码就跟之前block代码块里的代码一模一样. 也能起到同样的效果
When a work item is executed synchronously with the sync method, the program waits until execution finishes before the method call returns
When a work item is executed asynchronously with the async method, the method call returns immediately
假如我有A,B,C三个任务,
如果这三个任务都是同步执行, 程序将等待A 执行完毕之后, 再执行B, 再执行C
如果这三个任务都是是异步执行, 程序直接跳过A,B,C,执行后面的代码, 执行完毕之后, 再来执行A,B,C中的任务
无论任何队列, 其实都遵循FIFO(first in first out, 先进先出原则),
但是:
如下图所示
那么同步执行,异步执行,并发队列,串行队列互相组合又会发生什么样的情况呢? 这个时候, 就有四种情况需要分析了
/****************** -------- 异步执行 + 并发队列 -------- ******************/
- (void)asyncConcurrent {
/* 1. 创建一个并发队列 */
dispatch_queue_t concurrentQueue = dispatch_queue_create("download.tsaievan.com", DISPATCH_QUEUE_CONCURRENT);
/* 2. 将任务放到队列中, 下面的代码将三个任务放到队列中 */
dispatch_async(concurrentQueue, ^{
NSLog(@"download1-------%@",[NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^{
NSLog(@"download2-------%@",[NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^{
NSLog(@"download3-------%@",[NSThread currentThread]);
});
}
执行情况
可以看出, 开启了不同的线程, 任务完成的顺序也是随机的
但是不同的任务都开启一个独立的线程, 那我有100个任务,会开启100条线程吗? 答案是果断不会, 如下图所示
/****************** -------- 异步执行 + 串行队列 -------- ******************/
- (void)asyncSerial {
/* 1. 创建一个串行队列 */
dispatch_queue_t serialQueue = dispatch_queue_create("download.tsaievan.com", DISPATCH_QUEUE_SERIAL);
/* 2. 将不同的任务添加到队列中 */
dispatch_async(serialQueue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"download2--------%@",[NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"download3--------%@",[NSThread currentThread]);
});
}
执行情况:
可以看出的是: 异步执行 + 串行队列也开启了新的线程, 但是不管任务有多少个, 异步执行 + 同一条串行队列只开启一条新的线程, 任务的执行顺序也是按照队列中的顺序执行的, 因为同一条线程中, 必须等到前一个任务执行完毕后, 才能执行下一个任务.
/****************** -------- 同步执行 + 并发队列 -------- ******************/
- (void)syncConcurrent {
/* 1. 创建一条并发队列 */
dispatch_queue_t concurrentQueue = dispatch_queue_create("download.tsaievan.com", DISPATCH_QUEUE_CONCURRENT);
/* 2. 把任务放到队列中 */
dispatch_sync(concurrentQueue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
});
dispatch_sync(concurrentQueue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
});
dispatch_sync(concurrentQueue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
});
}
执行情况:
三个任务都在主线程中执行, 并没有开启新的线程. 但是, 是不是所有的同步执行的操作都在主线程中执行呢? 当然不是. 看下面的代码
- (void)syncConcurrentOnBackgroundThread {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self syncConcurrent];
});
}
我把同步执行+ 并发队列这个操作放到子线程去执行, 那么执行的线程就是子线程
所以说, 同步执行+ 并发队列, 并不会开启新的线程, 即使是并发队列, 也然并卵
/****************** -------- 同步操作 + 串行队列 -------- ******************/
- (void)syncSerial {
/* 1. 创建串行队列 */
dispatch_queue_t serialQueue = dispatch_queue_create("download.tsaievan.com", DISPATCH_QUEUE_SERIAL);
/* 2. 将任务放到队列中 */
dispatch_sync(serialQueue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"download2--------%@",[NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"download3--------%@",[NSThread currentThread]);
});
}
执行情况:
如果是在子线程中执行同步串行队列的操作, 当前的线程就是子线程
还有一个操蛋的全局并发队列和主队列, 这两个又是什么鬼呢?
全局并发队列就是我们常说的全局队列
比较特殊的是主队列
系统会把主队列中的任务放在主线程中执行
/****************** -------- 异步执行 + 主队列 -------- ******************/
- (void)asyncMainQueue {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"download1------%@",[NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"download2------%@",[NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"download3------%@",[NSThread currentThread]);
});
}
执行情况:
异步执行虽然有开启新线程的能力, 但是异步执行 + 主队列并不会开启新的线程, 任务都是在主线程中执行的
/****************** -------- 同步执行 + 主队列 -------- ******************/
- (void)syncMainQueue {
NSLog(@"------start-------");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"download1-------%@",[NSThread currentThread]);
});
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"download1-------%@",[NSThread currentThread]);
});
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"download1-------%@",[NSThread currentThread]);
});
NSLog(@"-------end---------");
}
执行情况:
直接崩溃了, 以前这种情况是会发生死锁的, 不知道是不是因为是XCode8.2的原因, 现在直接报错. 那么, 为什么会发生这种情况呢?
可以这样理解, 上图中, 执行syncMainQueue这个方法是在主线程中执行的, 你可以把它看做一个任务A, 这个任务A也是在主队列中的,那么代码执行到第179行的时候, 启动了任务B, 把任务B放进了主队列中, 由于是同步执行, 所以, 必须等待任务B执行完了之后才能继续向下执行, 但是主线程有任务A, 所以任务B无法放到主线程中去执行,任务B等待任务A执行, 任务A等待任务B执行, 这样就造成了死锁.
如图所示:
但是, 如果将同步执行+ 主队列的操作放到子线程中执行, 就不会造成死锁
那为什么同步执行 + 串行队列不会造成死锁呢?
同步执行是不会开启新的线程的, 如果当前线程是主线程, 则任务在主线程中执行. 如下图所示
说了这么多, 可能又有点晕, 其实这些应该在实际开发中慢慢体会, 碰到的情况多了, 自然而然就明白了. 现在, 我们只要记住下面的表格就可以了
原文地址: http://www.jianshu.com/p/0aeb2848780d
同步,异步,串行队列,并发队列,全局队列,主队列等概念的总结
标签:需要 梳理 并发 thread 参数 pre ndt 效果 顺序
原文地址:http://www.cnblogs.com/ibelieveyou/p/6780154.html