多线程工具之GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
使用GCD,不需要管理线程,线程管理完全托管给GCD。
用纯c写的,一般用block来描述
 
首先要了解同步和异步,串行和并行的区别:
 
同步:a请求b任务,只有b任务给予a反馈,a才能继续执行
异步:a请求b任务时,a无需等待b回应就可以继续执行其他操作
串行:一个任务完成下一个任务菜可能开始
并行:在同一时刻,两个任务开始执行,但互不干扰
 
1.dispatch queue
dispatch queue分成以下三种:
 
1)运行在主线程的Main queue,通过dispatch_get_main_queue获取。
 
2)并行队列global dispatch queue(可以多个线程并行,任务可以同时执行),通过dispatch_get_global_queue获取,由系统创建三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同。
 
3)串行队列serial queues(所有线程串行,或者只有一个线程,任务依次执行 )一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的。

当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。

 
serial queues通过dispatch_queue_create创建,可以使用函数dispatch_retain和dispatch_release去增加或者减少引用计数。
 
//创建串行的队列
    //第一个参数表示queue的名字,,,第二个参数表示queue的类型
    dispatch_queue_t queue_1 = dispatch_queue_create("queue.1", DISPATCH_QUEUE_SERIAL);
     
//创建并行的队列
    dispatch_queue_t queue_2 = dispatch_queue_create("queue.2", DISPATCH_QUEUE_CONCURRENT);
//获取全局并发的queue(属于并行队列)
    //第一个参数表示优先级,,,第二个参数暂时没用
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//获取管理主线程的queue(属于串行队列)
    //提交给main queue的任务可能不会立马被执行,而是在主线程的Run Loop检测到有dispatch 提交过来的任务时才会执行
    dispatch_queue_t main_queue = dispatch_get_main_queue();
 
2.提交任务
分为两种:同步提交和异步提交
 
两个参数:
。第一个参数表示提交到的queue
。第二个参数表示任务详情,这里用block的方式描述一个任务,原因很简单,Block也是 纯C实现的,而平时使用的Invocation或者target+selector方式都是面向对象的。
 
//获取全局并发的queue
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   
//1.同步提交
    //如果使用同步请求方式,会造成卡死当前线程的后果。
    // 同步提交任务后,先执行完block,然后dispatch_sync()返回
    dispatch_sync(global_queue, ^{
        NSLog(@"do something");
    });
    NSLog(@"OK");
   
 
//2.异步提交
    // 异步提交任务后,dispatch_async()函数直接返回,无需等待block 执行结束
    dispatch_async(global_queue, ^{
        NSLog(@"do something.....");
    });
    NSLog(@"OK.....");
 
//3.同步提交多次任务
    dispatch_queue_t queue_1 = dispatch_queue_create("queue.1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue_2 = dispatch_queue_create("queue.2", DISPATCH_QUEUE_CONCURRENT);
   
    //任务数量
    size_t count = 10;
   
    //同步提交多次任务
    //三个参数分别是:任务数,目标queue,任务描述
    // 如果目标queue是串行的,那么任务会依次执行,如果queue是并行的,那么任务会并发的执行,打印的顺序就会被打乱
    dispatch_apply(count, queue_2, ^(size_t i) {
        NSLog(@"%zu",i);
    });
    NSLog(@"---OK---");
   
 //比较同步提交多个任务和遍历数组哪个快   (在不关心数组顺序的前提下)
    //遍历数组
    NSMutableArray* array = [[NSMutableArray alloc]initWithCapacity:1000];
   
    for (int i =0; i<1000; i++) {
        [array addObject:[NSString stringWithFormat:@"%d",i]];
       
    }
   
    NSLog(@"start forin");
//数组遍历
    for (NSString* a in array) {
        NSLog(@"--%@",a);
    }
    NSLog(@"fisined forin");
 
    NSLog(@"start apply");
//同步提交多个任务
    dispatch_apply(array.count, queue_2, ^(size_t i) {
        NSLog(@"%@",array[i]);
    });
    NSLog(@"fisined apply");
 
3.死锁
 
同步提交在某种情况下会造成死锁,即卡死。
 
//主线程(属于串行队列)死锁
    //不会打印出任何东西
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    //同步执行
    dispatch_sync(main_queue, ^{
        NSLog(@"-----");
    });
    NSLog(@"OK");
程序默认是从上往下执行的,但是程序走到dispatch_sync时,又会先走block再返回到dispatch_sync,这样就会照成冲突,形成死锁
 
    //串行队列
    dispatch_queue_t queue_1 = dispatch_queue_create("queue.1", DISPATCH_QUEUE_SERIAL);
    //异步提交
    dispatch_async(queue_1, ^{
      
        //不会被打印
        //同步提交
        dispatch_sync(queue_1, ^{
            NSLog(@"bbb");
        });
        NSLog(@"ccccc");
       
    });
   
    NSLog(@"aaaa");
 
 
 
    死锁解决方案: 串行队列异步执行,并行队列同步执行。
       串行队列中 ,同步提交任务给本身队列,就会出现死锁。要想不出现死锁就把串行队列改为并行队列,或把同步提交任务改为异步提交。
       
 
4. Dispatch Group
 
什么是dispatch group,就像我们在NSOperation中添加依赖一样,如果我们一个任务需要等待其他一些任务完成才能执行时
 
4.1 提交任务
分为两步:
1.创建group
2.提交任务,并且把任务添加到group中
 
 
//1.创建group
 
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//2.提交一个任务给global_queue ,并且添加到group中
 
         / / global_queue并非是一个queue,但group必须是同一个
         / / group只有异步提交,没有同步提交
    dispatch_group_async(group, global_queue, ^{
       
        usleep(10000);
        NSLog(@"买锅");
       
    });
   
    dispatch_group_async(group, global_queue, ^{
        usleep(10000);
        NSLog(@"买菜");
       
    });
   
    dispatch_group_async(group, global_queue, ^{
        usleep(10000);
        NSLog(@"买饮料");
    });
 
//3.异步提交终极任务给queue ,main_queue
 
//终极任务就相当于operation1依赖于Operation2一样,只是operation1不能和之前提交任务一样,而是需要终极任务dispatch_group_notify提交
    //异步提交 不阻塞当前线程
    //要想阻塞当前线程,一直等待group所有任务结束,需要用到dispatch_group_wait
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"吃火锅");
    });
 
    //创建dispatch time
    //可以自定义超时时间,只等待一定的时间
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(200 * NSEC_PER_SEC));
 
//4.自定义超时时间
 
    //设置超时时间,阻塞当前线程
    dispatch_group_wait(group, time);
     //买饮料的时间过长,已经超过了等待的时间,所以很难再执行
    NSLog(@"....");
    NSLog(@"看电视");
 

转载于:https://www.cnblogs.com/gaominmin/p/4821527.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值