美文网首页
iOS多线程编程之GCD

iOS多线程编程之GCD

作者: 华子小筑 | 来源:发表于2015-12-02 11:30 被阅读40次

    文章资料来源《Objective-C高级编程》之GCD

    GCD是一种异步执行任务的技术,对于编程层面上异步执行就意味着创建一个线程(操作系统能夠進行運算调度的最小單位,是进程中一个单一顺序的控制流--from wiki)去执行Task;GCD提供了两种队列和相关API使得开发者只需要关心该选择哪种队列去执行任务即可;

    GCD的队列

    • serial queue 能够保证各个task在同一个线程中被执行并且执行顺序会严格的按照入队的顺序进行;
    • concurrent queue 各个task的执行互不影响,执行顺序上不确定,执行线程也不一定会相同;
    dispatch_queue_create 创建队列

    serial queue

      /*
     1>serial Queue:系统默认创建一个线程,队列中的任务是顺序执行
     2>创建多个serial queue 的执行是并发的没有顺序
     3>解决数据竞争问题:可以将任务放在serial queue中 保证任务按照顺序执行就能解决数据竞争
    */
    dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);
    

    concurrent queue

     /*
      1 concurrent queue 添加到队列中的任务会并发执行,没有顺序性
     */
    dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    

    非ARC下生成的队列还必须使用dispatch_release(Queue);来释放指定的队列

    Main Dispatch Queue and Global Dispatch Queue

    Main Dispatch Queue

      /*
      dispatch_get_main_queue
     (1)main queue 是一中serial queue,task是放在主线程的Runloop中执行的;
     (2)一些UI的更新操作需要放在主线程中,使用main queue是比较简单的
     */
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    

    global Dispatch Queue

     /*
       dispatch_get_global_queue
     (1)global queue 是一种concurrent queue,可以通过设置queue的priority指定执行的优先级;
     */
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    

    dispatch_set_target_queue

     /*
     dispatch_set_target_queue的第一个参数是指定要变更优先级的队列;指定与要使用优先级相同优先级的队列为第二个参数
     */
    dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
    dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
    dispatch_set_target_queue(serialqueue2, serialqueue1);
    /*  
    

    dispatch_after

    /*
      延迟若干时间处理某一个Task,只是追加task到某一个队列,并不一定立即执行task
    */
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"wait at least three seconds!!");
    });
    

    dispatch Group

    dispatch group 的出现可以解决多个并发task执行后能收到通知再执行其他任务操作的需求;

      /*
      1; 如果使用 serial queue 所有的task执行完毕后在执行done task
      2:如果使用 concurrent queue 所有的task执行后没办法 执行行done task 就需要 dispatch_group
     */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    //
    dispatch_group_async(group, queue, ^{
        NSLog(@"blok1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blok2");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blok3");
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"blok4");
    });
    // 监听group 中的task 是否已经全部执行完成
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"done!!");
    });
    //   dispatch_group_wait会hold住当前线程直到所有task执行完毕
    //    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"all finish!!!!");
    

    多个网络请求执行操作完成在执行下一步操作的需求如何实现?

     // 多个网络请求完成后再做新的任务
        dispatch_group_enter(group);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //网络请求操作1
            dispatch_group_leave(group);
        });
        dispatch_group_enter(group);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //网络请求操作2
            dispatch_group_leave(group);
        });
    

    dispatch_barrier_async

    多线程操作产生的一个问题就是数据资源的竞争,读写操作如何能保证线程安全性;dispatch_barrier_async提供了解决方案

     /*
       使用concurrent dispatch queue 和 dispatch barrier async 函数可实现高效率的数据库访问和文件读取
     */
    dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"task1forReading!");
    });
    dispatch_async(queue, ^{
        NSLog(@"task2forReading!");
    });
    dispatch_async(queue, ^{
        NSLog(@"task3forReading!");
    });
    dispatch_barrier_async(queue, ^{
        // 此taskforWriting 会等到加入concurrentQueue中的task执行完毕后,执行taskforWriting,等到该taskforWriting执行完毕后在执行 concurrentQueue中的task
        NSLog(@"taskforWriting!");
    });
    dispatch_async(queue, ^{
        NSLog(@"task4forReading!");
    });
    dispatch_async(queue, ^{
        NSLog(@"task5forReading!");
    });
    

    dispatch_sync

    /*
    dispatch_sync 函数意味着等待;它要等待task执行完毕后再做返回
    */
    //使用dispatch_sync 容易造成死锁
    //在主线程中执行以下源代码会造成死锁
    /*
      main_queue 是一个serialQueue ,使用dispatch_sync将task加入到mainqueue中task会等待mainqueue中的任务执行完成,而mainqueue又要等待task完成,由此造成了死锁;
     */
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    dispatch_sync(main_queue, ^{
        NSLog(@"hello dispatch_sync!");
    });
    //>2在主线程中执行以下源代码也会造成死锁
    dispatch_async(main_queue, ^{
       dispatch_sync(main_queue, ^{
           NSLog(@"hello!!");
       });
    });
    

    dispatch_apply

      NSMutableArray* tempArr  = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
       // 1 按照指定的次数将指定的Block追加到指定的Dispatch_Queue中,并等待全部处理执行结束
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_apply([tempArr count], queue, ^(size_t index) {
            // 要做数据更新操作
            NSLog(@"%d",index);
        });
        NSLog(@"task done");
        /*
         1 对数组进行循环遍历的方法
           1》 for循环
           2》 block
           3》 dispatch_apply
          2 dispatch_apply 要等待结束,最好和 dispatch_async函数混合使用
         */
    

    挂起队列和执行队列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //挂起队列
    dispatch_suspend(queue);
    //恢复指定队列
    dispatch_resume(queue);  
    

    dispatch_Semaphore

     // 1  向数组中增加对象由于内存错误导致异常的概率会很高
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSMutableArray* mutable_arr =[NSMutableArray array];
    for(int i = 0;i<100000;++i)
    {
       dispatch_async(queue, ^{
           [mutable_arr addObject:[NSNumber numberWithInt:i]];
       });
    }
    
    
    // 2 使用dispatch_semaphore进行更细粒度的线程管理
    dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    /*
      生成Dispatch Semahpore
      dispatch_Semahpore 的计数初始值设定为“1”
      这样能保证访问NSMutableArray类对象的线程,同时只有1个
     */
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    NSMutableArray* array =[NSMutableArray array];
    for(int i = 0;i<10000;i++)
    {
        dispatch_async(global_queue, ^{
            /*
             等待Dispatch Semaphore
             直到Dispatch Semphore的计数值达到大于等于1;
             */
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            /*
             由于dispatch Semaphore 的计数值达到大于等于1
             所以将Dispatch semaphore 的计数值减去1
             dispatch_semaphore_wait 函数执行返回
             执行到此 dispatch Semaphore的计数值恒为“0”
             */
            
            [array addObject:[NSNumber numberWithInt:i]];
            
            /*
             排他控制处理结束,所以通过dispatch_semaphore_signal函数 将
             Dispatch Semaphore的计数值加1
             如果有通过dispatch_semaphore_wait 函数 等待dispatch Semaphore 的计数值增加的线程 就由最先等待的线程执行
             */
            dispatch_semaphore_signal(semaphore);
    
        });
    }
    

    dispatch_once

    保证应用程序中只执行一次指定处理的API

     +(instancetype)shareInstance
        {
            static ViewController* _vc;
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                _vc =[[self alloc] init];
            });
            return _vc;
        }

    相关文章

      网友评论

          本文标题:iOS多线程编程之GCD

          本文链接:https://www.haomeiwen.com/subject/fpojhttx.html