码迷,mamicode.com
首页 > 编程语言 > 详细

多线程编程-002-GCD

时间:2018-11-14 22:34:37      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:c语言   serial   sof   imei   获取   central   效率   案例   upload   

 

什么是GCD

 

全称是Grand Central Dispatch,可译为“牛逼的中央调度器”,纯C语言,提供了非常多强大的函数

GCD的优势

GCD是苹果公司为多核的并行运算提出的解决方案

GCD会自动利用更多的CPU内核(比如双核、四核)

GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

 

GCD2个核心概念

 

1>任务:执行什么操作

2>队列:用来存放任务

GCD使用步骤

//?1.定制任务
确定想做的事情
//?2.将任务添加到队列中
GCD会自动将队列中的任务取出,放到对应的线程中执行
//任务的取出遵循队列的FIFO原则:先进先出,后进后出

程序员要做的是将任务添加到队列,队列按照程序员指定的方式调度任务

③同步/异步-并发/串行

同步:一个人没有结束,就不会执行下一个任务

异步:不用等待任务执行完毕,就会执行下一个任务

并发和串行主要影响:任务的执行方式

 

并发:允许多个任务同时执行

串行:一个任务执行完毕后,再执行下一个任务

1>同步执行(sync这一句不执行,就不会执行下一句)

dispatch_sync(dsipatch_queue_t queue, dispatch_block_t block);//queue 队列;block 任务

 //同步执行方法:(sync):这一句不执行完成,就不会执行下一个任务。同步线程是不会开启子线程
    //1.创建队列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //2.将任务添加到队列中
    //2.1定义一个任务--block
    void (^tasks)(void) = ^{
        NSLog(@"%@",[NSThread currentThread]);//主线程
    };
    //2.2添加任务到队列,并且会执行
    dispatch_sync(q, tasks);

2>异步执行(如果任务没有完成,可以不等待,异步执行下一个任务[具备开启线程的能力])

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

    //异步执行任务 如果任务没有执行完毕,可以不要等待,异步执行下一个任务。具备开启线程的能力。异步通常是多线程的代名词;
    //1.创建队列 并发队列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //2.将任务添加到队列中
    //2.1定义一个任务--block
    void (^tasks)(void) = ^{
        NSLog(@"%@",[NSThread currentThread]);//子线程
    };
    //3添加任务到队列
    dispatch_async(q, tasks);

同步和异步的区别:

//同步:只能在当前线程中执行任务,不具备开启新线程的能力
//异步:可以在新的线程中执行任务,具备开启新线程的能力

 

 

线程间通信

    //1指定任务的执行方法--异步
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //耗时操作
        NSLog(@"%@",[NSThread currentThread]);
        //更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"更新UI%@",[NSThread currentThread]);
        });
    });

利用GCD来加载图片

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURL * url = [NSURL URLWithString:@"https://a-ssl.duitang.com/uploads/item/201503/09/20150309162548_LnTA3.thumb.700_0.jpeg"];
        NSData * data = [NSData dataWithContentsOfURL:url];
        UIImage * image = [UIImage imageWithData:data];
        //更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
            [self.imageView sizeToFit];
            self.scrollView.contentSize = image.size;
        });
    });

从子线程回到主线程

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

 

队列

//-串行队列:一个接着一个地执行任务
//-并发队列:可以同时调度多个任务
//-任务执行函数(任务都需要在线程中执行)
//-同步执行:当前的任务不完成,不会执行下一个任务
//-异步执行:当前任务不完成,同样执行下一个任务
//-同步执行:不会到线程池里面去获取子线程
//-异步执行:只要有任务,就会到线程池里面去获取子线程(主队列除外)
 小结:
// -- 开不开线程取决于执行任务的函数,同步不开,异步开;
// -- 开几条线程,取决于队列,串行开一条,并发开多条(异步)由CPU决定条数

 

队列的类型

 

1->并发队列(Concurrent Dispatch Queue)

可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)

并发功能只有在异步(dispatch_async)函数下才有效

使用dispatch_queue_create 函数创建队列

dispatch_queue_t
dispatch_queue_create(const char *label, // 队列名称 
dispatch_queue_attr_t attr); // 队列的类型

dispatch_get_global_queue 获取全局的并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_CONCURRENT);
GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 队列的优先级
unsigned long flags); // 此参数暂时无用,用0即可

全局并发队列的优先级

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 //
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台

 

并发全局队列

dispatch_queue_t q = dispatch_queue_create("CC_GCD8", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d",[NSThread currentThread],i);
        });
    }
/*
电量优化、流量优化
      全局队列&串行队列:
         全局队列:并发,能够调度多个线程,执行效率高-耗电!
         串行队列:一个一个执行,执行效率低 - 省电
      判断依据:根据用户的上网方式
     Wifi:可以多开线程!
     流量:尽量少开线程
     几个典型的耗电场景:
        1.定位,GPS定位
        2.网络传输,在非Wifi环境
        3.CPU频率
        4.内存调度频率
        5.后台运行!
*/

 

2>串行队列(Serial Dispatch Queue)

让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

GCD中获得串行有2种途径

1>>使用dispatch_queue_create函数创建串行队列

// 创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL); 

2>>使用主队列(跟主线程相关联的队列)

//主队列是GCD自带的一种特殊的串行队列 放在主队列中的任务
//都会放到主线程中执行
//使用dispatch_get_main_queue()获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();

3->GCD调度组 dispatch_group_t

    //1.队列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //2.调度组
    dispatch_group_t g = dispatch_group_create();
    //3.添加任务,将队列调度任务。任务完成的时候,能够提醒
    dispatch_group_async(g, q, ^{
        NSLog(@"download A %@",[NSThread currentThread]);
    });
    dispatch_group_async(g, q, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"download B %@",[NSThread currentThread]);
    });
    dispatch_group_async(g, q, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"download C %@",[NSThread currentThread]);
    });
    
    //4.当所有任务执行完毕后,通知
//    dispatch_group_notify(g, q, ^{
//        NSLog(@"OK %@",[NSThread currentThread]);
//    });
    dispatch_group_notify(g, dispatch_get_main_queue(), ^{
        //更新UI,通知用户
        NSLog(@"OK %@",[NSThread currentThread]);//1
    });
    NSLog(@"Come Here ");

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

这个函数要等在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。(这个queue不能是全局的并发队列)

⑥案例

1>主线程同步死锁dispatch_sync

    //主队列: 专门负责在主线程上调度任务的一个队列!...>>不会开线程
    //1.队列
    dispatch_queue_t t = dispatch_get_main_queue();
    //dispatch_sync 一个接一个造成死锁 会崩溃
    //同步任务
    dispatch_sync(t, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"COme here");

2>主线程同步不死锁dispatch_async

  void (^task)(void) = ^{
        NSLog(@"这里 !!! %@",[NSThread currentThread]);
        //1.队列
        dispatch_queue_t t = dispatch_get_main_queue();
        //dispatch_sync 一个接一个造成死锁 会崩溃
        //同步任务
        dispatch_sync(t, ^{
            NSLog(@"%@",[NSThread currentThread]);
        });
    };
    dispatch_async(dispatch_get_global_queue(0, 0), task);

3>

//MARK:串行队列,同步执行
会不会开辟线程?不能【串并行不能决定是否开启子线程;异步才可以开启子线程】顺序执行吗?是
//MARK:串行队列,异步执行 
串行 决定怎么拿任务 会不会开辟线程?会顺序执行吗?会 是
//MARK: 并发队列,异步执行:
//会不会开辟线程?  顺序执行吗?   comeHere
//会            不是         不确定
//MARK: 并发队列,同步执行:
//会不会开辟线程?  顺序执行吗?   comeHere
//不会            是           最后
//MARK: 同步任务加强
在开发中,通常耗时操作放在后台执行,有的时候,任务之间有依赖关系 例如:登录》支付、下载
利用同步任务,能做到任务依赖关系,前一个任务是同步任务,不执行完,队列就不会调度后面的任务
//MARK:增强版同步任务
队列调度多个任务之前,指定一个同步任务,让所有的异步,等待同步任务执行完成,就是依赖关系。同步任务就相当于一个锁

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

多线程编程-002-GCD

标签:c语言   serial   sof   imei   获取   central   效率   案例   upload   

原文地址:https://www.cnblogs.com/StevenHuSir/p/iOS_GCD.html

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