码迷,mamicode.com
首页 > 移动开发 > 详细

iOS多线程编程(四)------ GCD(Grand Central Dispatch)

时间:2016-08-25 21:23:00      阅读:317      评论:0      收藏:0      [点我收藏+]

标签:

一、简介
是基于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(Grand Central Dispatch)

标签:

原文地址:http://blog.csdn.net/yj229201093/article/details/52303801

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!