iOS多线程-GCD 附带GCD相关代码

2017-07-04  本文已影响0人  wxkkkkk

多线程学习笔记-GCD


GCD、NSThread、NSOperation区别

1. NSThread
每个NSThread对象对应一个线程,真正最原始的线程。
1)优点:NSThread 轻量级最低,相对简单。
2)缺点:手动管理所有的线程活动,如生命周期、线程同步、睡眠等。
2. NSOperation
自带线程管理的抽象类。
1)优点:自带线程周期管理,操作上可更注重自己逻辑。
2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
3. GCD
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
1)优点:最高效,避开并发陷阱。
2)缺点:基于C实现。
4. 选择小结
1)简单而安全的选择NSOperation实现多线程即可。
2)处理大量并发数据,又追求性能效率的选择GCD。
3)NSThread本人选择基本上是在做些小测试上使用,当然也可以基于此造个轮子。


1.GCD的好处

2.线程、进程、任务与队列

GCD总结代码下载地址-GCD-wxk

3.GCD使用

// 创建队列
    // 串行队列的创建方法
    dispatch_queue_t queue_1 = dispatch_queue_create("wxk_queue_1", DISPATCH_QUEUE_SERIAL);
    // 并发队列的创建方法
    dispatch_queue_t queue_2 = dispatch_queue_create("wxk_queue_2", DISPATCH_QUEUE_CONCURRENT);
    // 创建全局并发队列
    dispatch_queue_t queue_3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

使用dispatch_queue_create来创建对象,需要传入两个参数,第一个参数表示队列的唯一标识符,用于DEBUG,可为空;第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL表示串行队列,DISPATCH_QUEUE_CONCURRENT表示并发队列。
使用dispatch_get_global_queue来创建全局并发队列。GCD默认提供了全局的并发队列,需要传入两个参数。第一个参数表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二个参数暂时没用,用0即可。

 // 同步执行任务
    dispatch_sync(queue_1, ^{
       // 这里写任务代码
    });
    
    // 异步执行任务
    dispatch_async(queue_1, ^{
       // 这里写任务代码
    });

4.GCD使用实例

4.1 并发队列 + 同步执行

#pragma mark - 并发队列-同步执行
- (void) concurrent_sync
{
    NSLog(@"并发队列-同步执行 -- 开始");
    // 并发队列的创建方法
    dispatch_queue_t queue_2 = dispatch_queue_create("wxk_queue_2", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    NSLog(@"并发队列-同步执行 -- 结束");
}
// 输出
2017-07-03 16:58:59.331 GCD[1319:535532] 并发队列-同步执行 -- 开始
2017-07-03 16:58:59.331 GCD[1319:535532] 线程1--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.332 GCD[1319:535532] 线程1--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.332 GCD[1319:535532] 线程2--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.332 GCD[1319:535532] 线程2--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.332 GCD[1319:535532] 线程3--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.333 GCD[1319:535532] 线程3--<NSThread: 0x60800006f880>{number = 1, name = main}
2017-07-03 16:58:59.333 GCD[1319:535532] 并发队列-同步执行 -- 结束

4.2并发队列 + 异步执行

#pragma mark - 并发队列-异步执行
- (void) concurrent_async
{
    NSLog(@"并发队列-异步执行 -- 开始");
    // 并发队列的创建方法
    dispatch_queue_t queue_2 = dispatch_queue_create("wxk_queue_2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    NSLog(@"并发队列-异步执行 -- 结束");
}
// 输出
2017-07-03 17:16:45.376 GCD[1351:567851] 并发队列-异步执行 -- 开始
2017-07-03 17:16:45.376 GCD[1351:567851] 并发队列-异步执行 -- 结束
2017-07-03 17:16:45.376 GCD[1351:568290] 线程2--<NSThread: 0x6000002659c0>{number = 4, name = (null)}
2017-07-03 17:16:45.376 GCD[1351:568189] 线程1--<NSThread: 0x608000262580>{number = 3, name = (null)}
2017-07-03 17:16:45.376 GCD[1351:568190] 线程3--<NSThread: 0x600000265800>{number = 5, name = (null)}
2017-07-03 17:16:45.377 GCD[1351:568290] 线程2--<NSThread: 0x6000002659c0>{number = 4, name = (null)}
2017-07-03 17:16:45.377 GCD[1351:568189] 线程1--<NSThread: 0x608000262580>{number = 3, name = (null)}
2017-07-03 17:16:45.377 GCD[1351:568190] 线程3--<NSThread: 0x600000265800>{number = 5, name = (null)}

4.3串行队列 + 同步执行

#pragma mark - 串行队列-同步执行
- (void) serial_sync
{
    NSLog(@"并发队列-异步执行 -- 开始");
    // 串行队列的创建方法
    dispatch_queue_t queue_1 = dispatch_queue_create("wxk_queue_1", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    NSLog(@"并发队列-异步执行 -- 结束");
}
// 输出
2017-07-03 17:24:09.906 GCD[1385:605920] 并发队列-异步执行 -- 开始
2017-07-03 17:24:09.907 GCD[1385:605920] 线程1--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.907 GCD[1385:605920] 线程1--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.907 GCD[1385:605920] 线程2--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.908 GCD[1385:605920] 线程2--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.908 GCD[1385:605920] 线程3--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.908 GCD[1385:605920] 线程3--<NSThread: 0x6000000673c0>{number = 1, name = main}
2017-07-03 17:24:09.908 GCD[1385:605920] 并发队列-异步执行 -- 结束

4.4串行队列 + 异步执行

#pragma mark - 串行队列-异步执行
- (void) serial_async
{
    NSLog(@"并发队列-异步执行 -- 开始");
    // 串行队列的创建方法
    dispatch_queue_t queue_1 = dispatch_queue_create("wxk_queue_1", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_1, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"并发队列-异步执行 -- 结束");
}
// 输出
2017-07-03 17:27:24.452 GCD[1405:625719] 并发队列-异步执行 -- 开始
2017-07-03 17:27:24.452 GCD[1405:625719] 并发队列-异步执行 -- 结束
2017-07-03 17:27:24.452 GCD[1405:626097] 线程1--<NSThread: 0x600000078a00>{number = 3, name = (null)}
2017-07-03 17:27:24.453 GCD[1405:626097] 线程1--<NSThread: 0x600000078a00>{number = 3, name = (null)}
2017-07-03 17:27:24.453 GCD[1405:626097] 线程2--<NSThread: 0x600000078a00>{number = 3, name = (null)}
2017-07-03 17:27:24.453 GCD[1405:626097] 线程2--<NSThread: 0x600000078a00>{number = 3, name = (null)}
2017-07-03 17:27:24.453 GCD[1405:626097] 线程3--<NSThread: 0x600000078a00>{number = 3, name = (null)}
2017-07-03 17:27:24.454 GCD[1405:626097] 线程3--<NSThread: 0x600000078a00>{number = 3, name = (null)}

5 主队列

5.1 主队列 + 同步执行

#pragma mark - 主队列-同步执行
- (void) main_sync
{
    NSLog(@"并发队列-异步执行 -- 开始");
    // 获取主队列
    dispatch_queue_t queue_main = dispatch_get_main_queue();
    dispatch_sync(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"并发队列-异步执行 -- 结束");
}
// 输出
2017-07-03 17:34:36.768 GCD[1457:663325] 并发队列-异步执行 -- 开始

卡住了,这是因为我们在主线程中执行这段代码。我们把任务放到了主队列中,也就是放到了主线程的队列中。而同步执行有个特点,就是对于任务是立马执行的。那么当我们把第一个任务放进主队列中,它就会立马执行。但是主线程现在正在处理main_sync方法,所以任务需要等main_sync执行完才能执行。而main_sync执行到第一个任务的时候,又要等第一个任务执行完才能往下执行第二个和第三个任务。

那么,现在的情况就是main_sync方法和第一个任务都在等对方执行完毕。这样大家互相等待,所以就卡住了,所以我们的任务执行不了,而且‘结束’也没有打印。

#pragma mark - 修改主队列main_sync方法卡住问题
- (void) advance_main_sync
{
    dispatch_queue_t queue_2 = dispatch_queue_create("wxk_queue_2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue_2, ^{
        [self main_sync];
    });
}
// 输出
2017-07-03 17:53:09.550 GCD[1541:728425] 并发队列-异步执行 -- 开始
2017-07-03 17:53:09.557 GCD[1541:728236] 线程1--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.557 GCD[1541:728236] 线程1--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.559 GCD[1541:728236] 线程2--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.561 GCD[1541:728236] 线程2--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.562 GCD[1541:728236] 线程3--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.563 GCD[1541:728236] 线程3--<NSThread: 0x60800007fd40>{number = 1, name = main}
2017-07-03 17:53:09.563 GCD[1541:728425] 并发队列-异步执行 -- 结束

5.2 主队列 + 异步执行

#pragma mark - 主队列+异步任务
- (void) main_async
{
    NSLog(@"并发队列-异步执行 -- 开始");
    // 获取主队列
    dispatch_queue_t queue_main = dispatch_get_main_queue();
    dispatch_async(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_main, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"并发队列-异步执行 -- 结束");
}
// 输出
2017-07-03 17:55:42.924 GCD[1561:745372] 并发队列-异步执行 -- 开始
2017-07-03 17:55:42.925 GCD[1561:745372] 并发队列-异步执行 -- 结束
2017-07-03 17:55:42.931 GCD[1561:745372] 线程1--<NSThread: 0x608000078400>{number = 1, name = main}
2017-07-03 17:55:42.931 GCD[1561:745372] 线程1--<NSThread: 0x608000078400>{number = 1, name = main}
2017-07-03 17:55:42.932 GCD[1561:745372] 线程2--<NSThread: 0x608000078400>{number = 1, name = main}
2017-07-03 17:55:42.932 GCD[1561:745372] 线程2--<NSThread: 0x608000078400>{number = 1, name = main}
2017-07-03 17:55:42.932 GCD[1561:745372] 线程3--<NSThread: 0x608000078400>{number = 1, name = main}
2017-07-03 17:55:42.933 GCD[1561:745372] 线程3--<NSThread: 0x608000078400>{number = 1, name = main}

6.GCD的其他用法

6.1线程之间的通讯

#pragma mark - 线程之间的通讯
- (void) exchange
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 这里执行耗时操作
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"耗时操作--%@",[NSThread currentThread]);
        }
        // 回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            // 做完耗时操作后,在主线程刷新UI
            NSLog(@"刷新UI--%@",[NSThread currentThread]);
        });
        
    });
}
// 输出
2017-07-04 14:33:56.055 GCD[951:186144] 耗时操作--<NSThread: 0x608000072b00>{number = 3, name = (null)}
2017-07-04 14:33:56.056 GCD[951:186144] 耗时操作--<NSThread: 0x608000072b00>{number = 3, name = (null)}
2017-07-04 14:33:56.062 GCD[951:185945] 刷新UI--<NSThread: 0x600000068ec0>{number = 1, name = main}

6.2 GCD栅栏方法dispatch_barrier_async

#pragma mark - 栅栏方法
- (void) barrier
{
    dispatch_queue_t queue_2 = dispatch_queue_create("wxk_queue_2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程1--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程2--%@",[NSThread currentThread]);
        }
    });
    dispatch_barrier_async(queue_2, ^{
        NSLog(@"栅栏方法--%@", [NSThread currentThread]);
    });
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程3--%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue_2, ^{
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"线程4--%@",[NSThread currentThread]);
        }
    });
}
// 输出
2017-07-04 15:24:53.985 GCD[1007:250229] 线程2--<NSThread: 0x600000268240>{number = 4, name = (null)}
2017-07-04 15:24:53.985 GCD[1007:250226] 线程1--<NSThread: 0x6000002683c0>{number = 3, name = (null)}
2017-07-04 15:24:53.985 GCD[1007:250226] 线程1--<NSThread: 0x6000002683c0>{number = 3, name = (null)}
2017-07-04 15:24:53.985 GCD[1007:250229] 线程2--<NSThread: 0x600000268240>{number = 4, name = (null)}
2017-07-04 15:24:53.985 GCD[1007:250229] 栅栏方法--<NSThread: 0x600000268240>{number = 4, name = (null)}
2017-07-04 15:24:53.986 GCD[1007:250229] 线程3--<NSThread: 0x600000268240>{number = 4, name = (null)}
2017-07-04 15:24:53.986 GCD[1007:250226] 线程4--<NSThread: 0x6000002683c0>{number = 3, name = (null)}
2017-07-04 15:24:53.986 GCD[1007:250229] 线程3--<NSThread: 0x600000268240>{number = 4, name = (null)}
2017-07-04 15:24:53.986 GCD[1007:250226] 线程4--<NSThread: 0x6000002683c0>{number = 3, name = (null)}

6.3 GCD的延时执行方法 dispatch_after

#pragma mark - 延时执行方法
- (void) dispatch_after
{
    NSLog(@"开始开始");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"3秒后执行这段代码");
    });
}
// 输出
2017-07-04 15:33:27.837 GCD[1048:271319] 开始开始
2017-07-04 15:33:30.838 GCD[1048:271319] 3秒后执行这段代码

6.4 GCD的一次性代码(只执行一次)dispatch_once

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 只执行1次的代码(这里面默认是线程安全的)
    });

6.5 GCD的快速迭代方法 dispatch_apply

#pragma mark - 快速迭代方法
- (void) dispatch_apply
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd------%@",index, [NSThread currentThread]);
    });
}
// 输出
2017-07-04 15:47:38.918 GCD[1088:305847] 0------<NSThread: 0x60000007efc0>{number = 1, name = main}
2017-07-04 15:47:38.918 GCD[1088:305902] 1------<NSThread: 0x60000026b780>{number = 3, name = (null)}
2017-07-04 15:47:38.918 GCD[1088:305903] 2------<NSThread: 0x60000026b640>{number = 4, name = (null)}
2017-07-04 15:47:38.918 GCD[1088:305905] 3------<NSThread: 0x60000026c5c0>{number = 5, name = (null)}
2017-07-04 15:47:38.919 GCD[1088:305847] 4------<NSThread: 0x60000007efc0>{number = 1, name = main}
2017-07-04 15:47:38.919 GCD[1088:305902] 5------<NSThread: 0x60000026b780>{number = 3, name = (null)}

6.6 GCD的队列组 dispatch_group

#pragma mark - GCD的队列组
- (void) dispatch_group
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"耗时操作1--%@",[NSThread currentThread]);
        }
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
        
        for (int i = 0; i < 2; i++)
        {
            NSLog(@"耗时操作2--%@",[NSThread currentThread]);
        }
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"等前面的异步操作都执行完毕后,回到主线程...");
    });
}
// 输出
2017-07-04 15:54:10.056 GCD[1132:331040] 耗时操作2--<NSThread: 0x608000265c80>{number = 3, name = (null)}
2017-07-04 15:54:10.056 GCD[1132:331025] 耗时操作1--<NSThread: 0x60800007af80>{number = 4, name = (null)}
2017-07-04 15:54:10.056 GCD[1132:331040] 耗时操作2--<NSThread: 0x608000265c80>{number = 3, name = (null)}
2017-07-04 15:54:10.056 GCD[1132:331025] 耗时操作1--<NSThread: 0x60800007af80>{number = 4, name = (null)}
2017-07-04 15:54:10.062 GCD[1132:330947] 等前面的异步操作都执行完毕后,回到主线程...

看了一些GCD的文章后总结了下,方便以后慢慢丰富GCD的知识总结代码下载地址-GCD-wxk

GCD.png
上一篇 下一篇

猜你喜欢

热点阅读