iOS 开发_GCD函数与队列二、面试相关知识

2018-12-21  本文已影响0人  iOS_PM_WEB_尛鹏

【作者前言】:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进!

1.应用场景:

多线程神器---GCD,很多开发的场景中,我们都会使用到。

2.实现目标:

针对面试中可能遇到的问题,进行反向的剖析知识点。

3.代码说明:【比喻~队列与函数存在一种关系:C4-2的组合关系】

1) 知识点预热:首先需要了解同步&异步、串行&并行的关系

小结:
dispatch_async() 和 dispatch_sync() 他们的作用是将 任务(block)添加进指定的队列中。并根据是否为sync决定调用该函数的线程是否需要阻塞。
!!!:这里调用该函数的线程并不执行 参数中指定的任务(block块),任务的执行者是GCD分配给任务所在队列的线程。
即 ---> 调用dispatch_sync() 和 dispatch_async() 的线程,并不一定是任务(block块)的真正执行者

2) 代码实操+详细解读分析
/** 主队列---串行同步 --测试
    不会开启线程  等待执行
 */
- (void)mainSyncTest {
    NSLog(@"0");
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
    
    NSLog(@"2");
}

/****************控制台输出结果*******************/
 0 --- >崩溃Thread 1: EXC_BAD_INSTRUCTION 造成死锁

/****************结果分析******************/
 打印 0 ---> 正常输出后,
 当前执行这个dispatch_get_main_queue()队列的是主线程。
 执行了dispatch_sync()函数后,将block(打印1) 添加到了main_queue中,
 同时调用dispatch_syn这个函数的线程(也就是主线程)会被阻塞,需要等待
 block(打印1)执行完成,而此时执行主线程队列任务的线程正是主线程,
 此时他处于阻塞状态,所以block(打印1)永远不会被执行,因此主线程一直处于阻塞状态。

 因此这段代码运行后,并非卡在block(打印1)中无法返回,而是根本无法执行到这个block(打印1)!
 导致你等我我等你,形成死锁。无法打印 1 和 2
/** 主队列---串行异步 --测试
    不会开启线程, 顺序执行
 */
- (void)mainAysncTest {
    NSLog(@"0");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
    NSLog(@"2");
}
/****************控制台输出结果******************/
 0 2 1
/****************结果分析******************/
  dispatch_get_main_queue()属于串行队列,顺序执行
  dispatch_async()异步调用,不需要等待直接输出执行结果,
  即 0 ---> 2 ---> 1
/** 全局队列---并行同步 --测试
     不会开辟线程!
 */
- (void)globalSyncTest {
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d -- %@",i,[NSThread currentThread]);
        });
    }
    for (long i = 0; i < 100000; i ++) {
        //相当于做个一定的延时处理...方便查看效果
    }
    NSLog(@"hello sync Global_Queue");
}

/****************控制台输出结果******************/
0 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
1 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
2 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
3 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
4 -- <NSThread: 0x6000003faa40>{number = 1, name = main}

hello sync Global_Queue
/****************结果分析******************/
dispatch_get_global_queue() 属于并行队列,结果无序
dispatch_sync() 同步调用,需要等待执行结束后在执行其他任务,
即 阻塞当前线程,顺序执行,故并行也无法发挥作用,需要一个等一个依次执行,
所以这里并没有开辟新的线程!
/** 全局队列---并行异步 --测试
 */
- (void)globalAsyncTest {
    for (int i = 0; i < 5; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d -- %@",i,[NSThread currentThread]);
        });
    }
    
    for (long i = 0; i < 100000; i ++) {
        //相当于做个一定的延时处理...方便查看效果
    }
    NSLog(@"hello async Global_Queue");
}

/****************控制台输出结果******************/
 0 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}
 2 -- <NSThread: 0x6000032ae0c0>{number = 6, name = (null)}
 1 -- <NSThread: 0x6000032adfc0>{number = 4, name = (null)}
 3 -- <NSThread: 0x600003292940>{number = 5, name = (null)}
 4 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}

 hello async Global_Queue
/****************结果分析******************/
 dispatch_get_global_queue() 属于并行队列,执行结果时序不一定
 dispatch_async()异步调用,不需要等待直接顺序执行,
 所以,线程并非只有一个,开辟了多个线程并行处理任务,输出的结果的顺序也不确定
/** 串行同步队列 --测试
    不开辟线程   顺序执行
 */
- (void)serialSyncTest {
    dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(serialQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    NSLog(@"hello sync serialQueue");
}
/****************控制台输出结果******************
 0 -- <NSThread: 0x600000365200>{number = 1, name = main}
 1 -- <NSThread: 0x600000365200>{number = 1, name = main}
 2 -- <NSThread: 0x600000365200>{number = 1, name = main}
 3 -- <NSThread: 0x600000365200>{number = 1, name = main}
 4 -- <NSThread: 0x600000365200>{number = 1, name = main}
 
 hello sync serialQueue
 */
/****************结果分析******************
 serialQueue 属于串行队列 不会开辟线程 顺序执行
 dispatch_sync()同步调用,需要等待 顺序执行,
 
 串行队列情况下,只能依次执行,同步调用 等待出结果,故输出如上
 */
/** 串行异步队列 --测试
    不开辟线程   顺序执行
 */
- (void)serialAsyncTest {
    dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 5; i ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
     NSLog(@"hello serial Queue");
}
/****************控制台输出结果******************
 hello serial Queue
 
 0 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 1 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 2 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 3 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 4 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 */
/****************结果分析******************
 serialQueue 属于串行队列 不会开辟线程 顺序执行
 dispatch_async()异步调用,不需要等待直接顺序执行,
 
 串行队列情况下,只能依次执行,异步调用直接出结果,故输出如上
 */
/** 并行同步 ---测试
    不会创建线程  顺序执行
*/
- (void)concurrentSyncTest {
    //创建并发队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("ypConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    NSLog(@"hello sync concurrent Queue");
    
}
/****************控制台输出结果******************
 0 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 1 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 2 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 3 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 4 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 
 hello sync concurrent Queue
 */

/****************结果分析******************
 concurrentQueue 属于并行队列,执行结果时序不一定
 dispatch_sync()同步调用,需要等待 顺序执行,
 只要同步 就等待执行, 所以没有开辟线程  结果如上
 */
/** 并行异步:*/
- (void)concurrentAsyncTest {
    //创建并发队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("ypconcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 5; i ++) {
        dispatch_async(concurrentQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    for (long i = 0; i < 100000; i ++) {
        //相当于做个一定的延时处理...方便查看效果
    }
    NSLog(@"hello concurrent Queue");
    
}
/****************控制台输出结果******************/
 0 -- <NSThread: 0x600001633600>{number = 3, name = (null)}
 3 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
 2 -- <NSThread: 0x60000160d380>{number = 4, name = (null)}
 1 -- <NSThread: 0x600001633500>{number = 6, name = (null)}
 4 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
 
 hello concurrent Queue
/****************结果分析******************/
 concurrentQueue 属于并行队列,执行结果时序不一定
 dispatch_async() 异步调用,不需要等待直接顺序执行,
 所以,线程并非只有一个,开辟了多个线程并行处理任务,输出的结果的顺序也不确定
上一篇 下一篇

猜你喜欢

热点阅读