ios多线程编程(四)------gcd(grandcentraldispatch)

建古 建古     2022-12-06     200

关键词:

一、简介
是基于C语言开发的一套多线程开发机制,也是目前苹果官方推荐的多线程开发方法,用起来也最简单,只是它基于C语言开发,并不像NSOperation是面向对象的开发,而是完全面向过程的。如果使用GCD,完全由系统管理线程,我们不需要编写线程代码。只需定义想要执行的任务,然后添加到适当的调度队列(dispatch_queue).GCD会负责创建线程和调度你的任务,系统会直接提供线程管理。

二、任务和队列
GCD中有两个核心概念
(1)任务:执行什么操作
(2)队列:用来存放任务
GCD的使用就两个步骤
(1)定制任务
(2)确定想做的事情
将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行
提示:任务的取出遵循队列的FIFO原则:先进先出,后进后出

三、执行任务
1、GCD中有2个用来执行任务的函数
说明:把右边的参数(任务)提交给左边的参数(队列)进行执行
(1)用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
参数说明:queue:队列; block:任务
(2)用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

2、同步和异步的区别
同步:在当前线程中执行
异步:在另一条线程中执行

四、队列
1、GCD的队列可以分为2大类型
(1)并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数才有效

(2)串行队列(Serial Dispatch Queue):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

2、补充说明
有4个术语比较容易混淆:同步、异步、并发、串行(在博客 多线程编程(-)—-概念 也提到了)
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行决定了任务的执行方式
并发:多个任务并发执行
串行:一个任务执行完毕后,再执行下一个任务

五、(同步/异步)串行队列和(同步/异步)并发队列开启线程的总结 (代码示例)
说明:
(1)同步函数不具备开启线程的能力,无论是什么队列都不会开启线程;异步函数具备开启线程的能力,开启几条线程有队列决定(串行队列只会开启一条新的线程,并发队列会开启多条线程)
(2) MRC下凡是函数中,各种函数名中带有create\\copy\\new\\retain等字眼,都需要在不需要使用这个数据的时候进行release
ARC下GCD的数据类型不需要再作release
CF(core Foundation)的数据在ARC环境下还是需要release
(3) 异步函数具备开线程的能力,但不一定会开线程

1、异步并发队列(同时开启N个线程)

/**
 *  异步并发队列
 */
- (void)asynchronousConcurrent
    NSLog(@"异步函数往并发队列中添加任务");
    NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

    // 1、创建并发队列
    // 方法一 和创建串行队列一样
    //    dispatch_queue_t queue = dispatch_queue_create("asynConcurrent", DISPATCH_QUEUE_CONCURRENT);
    // 方法二 获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2、添加任务到队列
    dispatch_async(queue, ^
        NSLog(@"下载图片1 ------ %@", [NSThread currentThread]);
        [self loadImage:1];
    );

    dispatch_async(queue, ^
        NSLog(@"下载图片2------ %@", [NSThread currentThread]);
        [self loadImage:2];
    );

    dispatch_async(queue, ^
        NSLog(@"下载图片3 ------ %@", [NSThread currentThread]);
        [self loadImage:3];
    );

    NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果 开启多个线程,并发执行。没有先后顺序(有的话也是刚好巧合而已) 可以看number 可以看做线程值
    /**
     第一次执行
     2016-08-24 12:53:24.026 YJGCDDemo[1220:24092] 异步函数往并发队列中添加任务
     2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>number = 1, name = main
     2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>number = 1, name = main
     2016-08-24 12:53:24.027 YJGCDDemo[1220:24126] 下载图片1 ------ <NSThread: 0x7f81baf25e90>number = 2, name = (null)
     2016-08-24 12:53:24.027 YJGCDDemo[1220:24128] 下载图片2------ <NSThread: 0x7f81bacc5fe0>number = 3, name = (null)
     2016-08-24 12:53:24.027 YJGCDDemo[1220:24127] 下载图片3 ------ <NSThread: 0x7f81baf81ac0>number = 4, name = (null)

     第二次执行
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 异步函数往并发队列中添加任务
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>number = 1, name = main
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>number = 1, name = main
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24126] 下载图片2------ <NSThread: 0x7f81baf25e90>number = 2, name = (null)
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24260] 下载图片3 ------ <NSThread: 0x7f81baf7f660>number = 7, name = (null)
     2016-08-24 12:53:32.427 YJGCDDemo[1220:24153] 下载图片1 ------ <NSThread: 0x7f81baf81ac0>number = 6, name = (null)

     */

2、异步串行队列(会开启线程,但是只开启一个线程)

/**
 *  异步串行队列
 */
- (void)asynchronousSerial

    NSLog(@"用异步函数往串行队列中添加任务");
    NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

    //1. 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("asynSerial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^
        NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
        [self loadImage:1];
    );


    dispatch_async(queue, ^
        NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
        [self loadImage:2];
    );

    dispatch_async(queue, ^
        NSLog(@"下载图片3 --- %@", [NSThread currentThread]);
        [self loadImage:3];
    );

    NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果:异步串行队列,会开启一个线程,顺序执行。 看运行结果也可以看出,图片是一张下载完在下载下一张的。
    /**
     2016-08-24 12:39:14.195 YJGCDDemo[942:16507] 用异步函数往串行队列中添加任务
     2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程1111 ---- <NSThread: 0x7f8ed1f05f90>number = 1, name = main
     2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程2222 ---- <NSThread: 0x7f8ed1f05f90>number = 1, name = main
     2016-08-24 12:39:14.196 YJGCDDemo[942:16622] 下载图片1 --- <NSThread: 0x7f8ed1c43c00>number = 2, name = (null)
     2016-08-24 12:39:14.261 YJGCDDemo[942:16622] 下载图片2 --- <NSThread: 0x7f8ed1c43c00>number = 2, name = (null)
     2016-08-24 12:39:14.303 YJGCDDemo[942:16622] 下载图片3 --- <NSThread: 0x7f8ed1c43c00>number = 2, name = (null)

     */

3、同步并发队列(不会开启新的线程,并发队列失去并发的功能)

/**
 *  同步并发队列
 */
- (void)synchronousConcurrent
        NSLog(@"用同步函数往并发队列中添加任务");
        NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

        // 1.创建并发队列
        // 方式一 一般都使用这种方式获取
    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        // 方式二 和创建串行队列一样
        dispatch_queue_t queue = dispatch_queue_create("syncConcurrentncy", DISPATCH_QUEUE_CONCURRENT);

        // 2.加添任务到队列
        dispatch_sync(queue, ^
            NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
            [self loadImage:1];
        );

        dispatch_sync(queue, ^
            NSLog(@"下载图片2 ---- %@", [NSThread currentThread]);
            [self loadImage:2];
        );

        dispatch_sync(queue, ^
            NSLog(@"下载图片3 ---- %@", [NSThread currentThread]);
            [self loadImage:3];
        );

        NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果 和同步串行队列一样 这边并发队列效果失效,不会开启线程。
    /**
     2016-08-24 11:20:44.153 YJGCDDemo[43913:3002870] 用同步函数往并发队列中添加任务
     2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 主线程1111 ---- <NSThread: 0x7f8742604eb0>number = 1, name = main
     2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 下载图片1 ---- <NSThread: 0x7f8742604eb0>number = 1, name = main
     2016-08-24 11:20:44.433 YJGCDDemo[43913:3002870] 下载图片2 ---- <NSThread: 0x7f8742604eb0>number = 1, name = main
     2016-08-24 11:20:44.475 YJGCDDemo[43913:3002870] 下载图片3 ---- <NSThread: 0x7f8742604eb0>number = 1, name = main
     2016-08-24 11:20:44.508 YJGCDDemo[43913:3002870] 主线程2222 ---- <NSThread: 0x7f8742604eb0>number = 1, name = main

     */

4、同步串行队列(不会开启新的线程)

/**
 *  同步串行队列
 */
- (void)synchronousSerial
    NSLog(@"用同步函数往串行队列中添加任务");
    NSLog(@"主线程111----- %@", [NSThread currentThread]);

    // 1、创建串行队列 // DISPATCH_QUEUE_SERIAL 串行队列 也可以为NULL NULL时 默认是 串行队列; DISPATCH_QUEUE_CONCURRENT 并发队列
    dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);

    // 2、添加任务到队列中执行
    dispatch_sync(queue, ^
        // 此块代码没有任何意义,只是为了体现同步串行队列的效果, 只能执行完了 才能执行面下的,
        for (int i = 0; i < 30000; i++) 
            //
            NSLog(@"%i", i);
        
        NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
        [self loadImage:1];
    );

    dispatch_sync(queue, ^
        for (int i = 0; i < 30000; i++) 
            //
            NSLog(@"%i", i);
        
        NSLog(@"下载图片2 -- %@", [NSThread currentThread]);
        [self loadImage:2];
    );

    dispatch_sync(queue, ^
        for (int i = 0; i < 30000; i++) 
            //
            NSLog(@"%i", i);
        
        NSLog(@"下载图片3 -- %@", [NSThread currentThread]);
        [self loadImage:3];
    );

    NSLog(@"主线程222----- %@", [NSThread currentThread]);


    // 打印结果就是同步按顺序执行。 每个任务按顺序执行,不开启线程
    /**
     2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 用同步函数往串行队列中添加任务
     2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 主线程111----- <NSThread: 0x7fd5dbc00dd0>number = 1, name = main
     2016-08-24 10:52:55.050 YJGCDDemo[43413:2986818] 下载图片1 ---- <NSThread: 0x7fd5dbc00dd0>number = 1, name = main
     2016-08-24 10:52:55.580 YJGCDDemo[43413:2986818] 下载图片2 -- <NSThread: 0x7fd5dbc00dd0>number = 1, name = main
     2016-08-24 10:52:55.616 YJGCDDemo[43413:2986818] 下载图片3 -- <NSThread: 0x7fd5dbc00dd0>number = 1, name = main
     2016-08-24 10:52:55.644 YJGCDDemo[43413:2986818] 主线程222----- <NSThread: 0x7fd5dbc00dd0>number = 1, name = main

     */

六、常用方法 在Demo中的CommonMethodsViewCotroller类

1、后台运行

 dispatch_async(dispatch_get_global_queue(0, 0), ^
        // something
    );

2、主线程执行

dispatch_async(dispatch_get_main_queue(), ^
        // something
    );

3、一次性执行 dispatch_once()

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        // code to be execution once
        NSLog(@"改行代码只执行一次");
    );

4、延迟N秒执行 (这边列举了四种方式) dispatch_time()

    NSLog(@"打印线程----- %@", [NSThread currentThread]);
    // 延时执行方式一 使用NSObject的方法
    // 2秒后再调用self的run方法
//    [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];

    // 延迟执行方式二 使用GCD函数
       // 在同步函数中执行
        // 注意 如果使用异步函数 dispatch_async 那么[self performSelector:@selector(loadImage) withObject:nil afterDelay:5.0]; 不会被执行
//    dispatch_queue_t queue = dispatch_queue_create("yangjian.net.cn", 0);
//    dispatch_sync(queue, ^
//        [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];
//    );

    // 延迟执行方式三 可以安排其线程---> 主队列
//    dispatch_queue_t queue = dispatch_get_main_queue();
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^
//        NSLog(@"主队列--延迟执行------%@",[NSThread currentThread]);
//        [self gcdLoadImage];
//    );

    // 延迟执行方式四 可以安排其线程---> 并发队列
    //1、获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //2、计算任务执行的时间
    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
    //3、会在when这个时间点,执行queue中的这个任务
    dispatch_after(when, queue, ^
        NSLog(@"并发队列--延迟执行 ---- %@", [NSThread currentThread]);
        [self gcdLoadImage];
    );

5、执行某个代码片段N次 dispatch_apply()

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(4, globalQueue, ^(size_t index) 
        // 执行4次
    );

6、队列组的使用 dispatch_group_async()

    // 需求
    //1  分别异步执行2个耗时的操作
    //2  等两个异步操作都执行完毕后,再回到主线程执行操作

//   如果想要快速高效地实现上述需求,可以考虑用队列组

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^
        // 并发执行的线程一
    );

    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^
        // 并发执行的线程二
    );

    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^
        // 等前面的异步操作都执行完毕后,回到主线程
    );

6、dispatch_barrier_async()

/**
 *   使用此方法创建的任务首先会查看队列中有没有别的任务要执行,如果有,则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等待此方法中任务执行后才能执行。(利用这个方法可以控制执行顺序,例如前面先加载最后一张图片的需求就可以先使用这个方法将最后一张图片加载的操作添加到队列,然后调用dispatch_async()添加其他图片加载任务)
 */
- (void)barrier
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t queue = dispatch_queue_create("RICHARD", DISPATCH_QUEUE_CONCURRENT); // 创建并发队列

    dispatch_async(queue, ^
        NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://atth.eduu.com/album/201203/12/1475134_1331559643qMzc.jpg"];

        // 回到主线程
        dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
        dispatch_async(mainQueue1, ^
            self.imageViewOne.image = image;
        );
    );

    dispatch_async(queue, ^
        NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
    );

    dispatch_barrier_async(queue, ^
        NSLog(@"dispatch_barrier_async 下载图片3  --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
        dispatch_async(main_queue, ^
            self.imageViewThree.image = image;
        );
    );



    dispatch_async(queue, ^
        NSLog(@"下载图片4 --- %@", [NSThread currentThread]);
    );

    dispatch_async(queue, ^
        NSLog(@"下载图片5 --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        dispatch_async(main_queue, ^
            self.imageViewTwo.image = image;
        );
    );


    // 打印结果分析:1、 12 执行玩完 执行3  再执行45  2、 12顺序不定 45顺序不定
    /**
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367515] 下载图片2 --- <NSThread: 0x7ff720f13ac0>number = 47, name = (null)
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367518] 下载图片1 --- <NSThread: 0x7ff720e1c5d0>number = 48, name = (null)
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367102] dispatch_barrier_async 下载图片3  --- <NSThread: 0x7ff720d9b7d0>number = 43, name = (null)
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367293] 下载图片4 --- <NSThread: 0x7ff720c9e250>number = 45, name = (null)
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367516] 下载图片5 --- <NSThread: 0x7ff720dba290>number = 46, name = (null)

     */



七、代码示例 在Demo中的CommonMethodsViewCotroller类
下载两张照片完后,合并照片。(两种方式)

/**
 *  合并图片(方式一)
 */
- (void)mergeImage

//    // 获取全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//
//    // 获取主队列
//    dispatch_queue_t mainQueue = dispatch_get_main_queue();


    dispatch_async(global_queue, ^
        // 下载图片1
        UIImage *image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        NSLog(@"图片1下载完成----%@", [NSThread currentThread]);

        UIImage *image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];

        NSLog(@"图片2下载完成----%@", [NSThread currentThread]);

        // 回到主线程显示图片
        dispatch_async(main_queue, ^
            NSLog(@"显示图片---%@", [NSThread currentThread]);
            self.imageViewOne.image = image1;
            self.imageViewTwo.image = image2;

            // 合并两张图片
            UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
            [image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
            [image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
            self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
            // 关闭上下文
            UIGraphicsEndImageContext();

            NSLog(@"图片合并完成----%@", [NSThread currentThread]);

        );
    );

    // 打印结果 需要等图片1下载完 在下载图片2 再回到主线程
    /**
     2016-08-24 16:58:40.123 YJGCDDemo[3480:125975] 图片1下载完成----<NSThread: 0x7ff65acd85f0>number = 3, name = (null)
     2016-08-24 16:58:40.319 YJGCDDemo[3480:125975] 图片2下载完成----<NSThread: 0x7ff65acd85f0>number = 3, name = (null)
     2016-08-24 16:58:40.319 YJGCDDemo[3480:125910] 显示图片---<NSThread: 0x7ff65ad00dd0>number = 1, name = main
     2016-08-24 16:58:40.335 YJGCDDemo[3480:125910] 图片合并完成----<NSThread: 0x7ff65ad00dd0>number = 1, name = main
     */
    // 效率不高 需要等图片1,图片2都下载完了后才合并
    // 优化 使用队列组可以让图片1 图片2的下载任务同事进行,且当两个下载任务都完成的时候回到主线程进行显示。


/**
 *  使用队列组解决(方式二)
 */
- (void)groupMergeImage
    //步骤
    //  1、创建一个队列组
    //  2、开启一个任务下载图片1
    //  3、开启一个任务下载图片2
    //  同时执行下载图片1  和 下载图片2操作
    //  4、等group中的所有任务都执行完毕,再回到主线程执行其他操作

    // 1、创建一个队列租
    dispatch_group_t group = dispatch_group_create();

    // 2、开启一个任务下载图片1
    __block UIImage *image1 = nil;
    dispatch_group_async(group, global_queue, ^
        image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        NSLog(@"图片1下载完成--- %@", [NSThread currentThread]);
    );

    // 3、开启一个任务下载图片2
    __block UIImage *image2 = nil;
    dispatch_group_async(group, global_queue, ^
        image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
        NSLog(@"图片2下载完成--- %@", [NSThread currentThread]);
    );

    // 同时执行下载图片1\\下载图片2操作

    // 4、等group重的所有任务都执行完毕,再回到主线程执行其他操作
    dispatch_group_notify(group, main_queue, ^
        NSLog(@"显示图 --- %@", [NSThread currentThread]);
        self.imageViewOne.image = image1;
        self.imageViewTwo.image = image2;

        // 合并两张图片
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
        [image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
        [image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
        self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭上下文
        UIGraphicsEndImageContext();

        NSLog(@"图片合并完成 --- %@", [NSThread currentThread]);
    );


    // 同时开启两个线程 分别下载图片 会比上面的效率高一点
    /**
     2016-08-24 16:58:03.785 YJGCDDemo[3467:125346] 图片1下载完成--- <NSThread: 0x7f8d13cc61c0>number = 3, name = (null)
     2016-08-24 16:58:03.978 YJGCDDemo[3467:125349] 图片2下载完成--- <NSThread: 0x7f8d13ece620>number = 4, name = (null)
     2016-08-24 16:58:03.978 YJGCDDemo[3467:125303] 显示图 --- <NSThread: 0x7f8d13e052b0>number = 1, name = main
     2016-08-24 16:58:03.995 YJGCDDemo[3467:125303] 图片合并完成 --- <NSThread: 0x7f8d13e052b0>number = 1, name = main

     */


八、线程间通信

// 从子线程回到主线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
     // 执行耗时的异步操作
     dispatch_async(dispatch_get_main_queue(), ^
          //回到主线程,执行UI刷新操作
     );
 );

九、Operation和GCD的对比
优点: 不需要关心线程管理,数据同步的问题;
区别:
1、性能:GCD更接近底层,而NSOperation则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。
2、从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持
3、如果异步操作的国学更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势

十、总结
学了两天,对gcd有一些的了解,能在项目中使用多线程,不过这边也要避免很多死锁的问题,后期有时间再整理出来。四天左右把iOS多线程的几种方法都整理了下,写了demo。也算对自己的一个小小总结。
总结两点:
1、线程运行方式
dispatch_async 异步执行
dispatch_sync 同步执行
dispatch_delay 延迟执行
2、处理任务对象
dispatch_get_main_queue 主线程队列(UI线程队列)
dispatch_get_global_queue 并发线程队列
串行队列

demo地址: http://download.csdn.net/detail/yj229201093/9611939
参考链接:http://www.cnblogs.com/wendingding/p/3806821.html
感谢各路大神的博客,学无止境…

ios多线程编程——gcd与nsoperation总结

...来,我个人(可能还有很多同学),对多线程编程都存在一些误解。一个很明显的表现是,很多人有这样的看法:新开一个线程,能提高速度,避免阻塞主线程毕竟多线程嘛,几个线程一起跑任... 查看详情

《objective-c高级编程》干货三部曲:gcd篇

我们知道在iOS开发中,一共有四种多线程技术:pthread,NSThread,GCD,NSOperation:-前两者是面向线程开发的多线程技术,需要开发者自己去维护线程的生命周期,比较繁琐。-后两者是面向队列开发的多线程技术,开发者仅仅定义... 查看详情

ios多线程之gcd的使用

 在iOS开发中,遇到耗时操作,我们经常用到多线程技术。GrandCentralDispatch(GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列(dispatchqueue)。GCD会负责创建线程和调度你的任务,系... 查看详情

ios底层探索之多线程—gcd源码分析(栅栏函数)(代码片段)

...f0c;调度组等底层源码进行探索分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD不同队列源 查看详情

ios底层探索之多线程—gcd不同队列源码分析(代码片段)

...篇博客将继续介绍GCD的队列和源码分析。iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列1.主队列分析查看主队列的api如下图&# 查看详情

ios底层探索之多线程—gcd源码分析(函数的同步性异步性单例)(代码片段)

...;那么本篇博客继续源码的探索分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD不同队列源码... 查看详情

ios底层探索之多线程—gcd源码分析(事件源dispatch_source)(代码片段)

...客将对事件源dispatch_source进行分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD不同队列源码分... 查看详情

ios底层探索之多线程—gcd源码分析(信号量dispatch_semaphore_t)(代码片段)

...;本篇博客将对信号量进行探索分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD不同队列源码... 查看详情

ios多线程开发——gcd的使用与多线程开发浅析

    对于iOS多线程开发,我们时刻处于学习之中,在看书中,看文档中,项目开发中,都可以去提高自己。最近刚看完了《Objective-C高级编程iOS与OSX多线程和内存管理》这本书后,对多线程有了更为深入的理解,故... 查看详情

巧谈gcd

谈到iOS多线程,一般都会谈到四种方式:pthread、NSThread、GCD和NSOperation。其中,苹果推荐也是我们最经常使用的无疑是GCD。对于身为开发者的我们来说,并发一直都很棘手,如果对GCD的理解不够透彻,那么iOS开发的历程绝对不会... 查看详情

ios多线程:『gcd』详尽总结(代码片段)

本文用来介绍iOS多线程中GCD的相关知识以及使用方法。这大概是史上最详细、清晰的关于GCD的详细讲解+总结的文章了。通过本文,您将了解到:1.GCD简介2.GCD任务和队列3.GCD的使用步骤4.GCD的基本使用(6种不同组合区别)5.GCD线程... 查看详情

gcd的日常

谈到iOS多线程,一般都会谈到四种方式:pthread、NSThread、GCD和NSOperation。其中,苹果推荐也是我们最经常使用的无疑是GCD。对于身为开发者的我们来说,并发一直都很棘手,如果对GCD的理解不够透彻,那么iOS开发的历程绝对不会... 查看详情

ios多线程编程之nsthread的使用

1、简介:1.1iOS有三种多线程编程的技术,分别是:1.、NSThread 2、CocoaNSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)3、GCD  全称:GrandCentralDispatch( iOS多线程编程之GrandCentr 查看详情

ios底层探索之多线程(十五)—@synchronized源码分析(代码片段)

对于多线程你了解多少?对于锁你又了解多少?锁的原理你又知道吗?iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS... 查看详情

nsoprationqueue与gcd的区别与选用

...实现隐藏的神奇技术,我们能够通过GCD和block轻松实现多线程编程,有时候,GCD相比其他系统提供的多线程方法更加有效,当然,有时候GCD不是最佳选择,另一个多线程编程的技术NSOprationQueue让我们能够将后台线程以队列方式依... 查看详情

swift-多线程实现方式-grandcentraldispatch(gcd)

1,Swift继续使用Object-C原有的一套线程,包括三种多线程编程技术:(1)Thread(2)CocoaOperation(Operation和OperationQueue)(3)GrandCentralDispath(GCD)2,本文着重介绍GrandCentralDispath(GCD)GCD是Apple开发的一个多核编程的解决方法,基... 查看详情

多线程编程-002-gcd(代码片段)

p.p1margin:0.0px0.0px0.0px18.0px;text-indent:-18.0px;font:14.0px"YuantiSC";color:#000000 ①什么是GCD p.p1margin:0.0px0.0px0.0px18.0px;text-indent:-18.0px;font:14.0px"YuantiSC";color:#000000全 查看详情

ios底层探索之多线程(十四)—关于@synchronized锁你了解多少?(代码片段)

对于多线程你了解多少?对于锁你又了解多少?锁的原理你又知道吗?iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS... 查看详情