GCD笔记

  苹果官方说明,GCD是异步执行任务的技术之一,通常将应用程序中记述的线程管理用的代码在系统级中实现。开发者只须要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。因为线程管理是做为系统的一部分来实现的,所以能够统一管理,也能够执行任务。以下:数据库

 
 

    //串形队列 第二个参数最好为 NULL 参考源码编程

  dispatch_queue_t serialQueue = dispatch_queue_create("com.example.gcd.mySerialQueue", NULL);

     //并行队列 第二个参数最好为 DISPATCH_QUEUE_CONCURRENT数组

    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.gcd.myCurrentQueue", DISPATCH_QUEUE_CONCURRENT);安全

  dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 长时间处理 如:数据库访问
 dispatch_async(dispatch_get_main_queue(), ^{ //主线程更新
 }); });

其实只有第一行代码表示让处理在后台执行。也只有一行代码让处理在主线程中执行。多线程

在GCD以前,Cocoa框架也提供NSObject类来实现一样的效果:并发

    //执行后台线程
    [self performSelectorInBackground:@selector(doWork) withObject:nil];
- (void)doWork{
    // 长时间处理  如:数据库访问
    // ...........................
    //处理结束  ,主线城处理结果
    [self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];
}

- (void)doneWork{
    //主线程执行    如用户界面更新
}

这个方法的确要比NSThread提供的简单,可是相比于GCD仍是繁琐了。在多线程编程中,因为CPU一次只能执行一个命令,GCD的优点就更加明显。app

 

------Dispatch Queue的种类框架

    //获取主线程 属于serial queue
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //高优先级获取方法 属于concurrent queue
    dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    //默认先级获取方法 属于concurrent queue
    dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //低优先级获取方法 属于concurrent queue
    dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    //后台优先级获取方法 属于concurrent queue
    dispatch_queue_t globalDispatchQueueBg = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);--

-----指定优先级 ,若是在多个serial dispatch queue中用此函数制定目标为某一个serial dispatch queue,那么本来能够并发执行的多个serial dispatch queue,在目标serial dispatch queue上只能同时执行一个处理。异步

   //指定变动优先级 第一个参数若是是系统提供的如main dispatch queue 和  global dispatch queue 均不可指定
    //第一个参数指定变动优先级   第二个参数指定与要使用的执行的相同优先级
    dispatch_set_target_queue(globalDispatchQueueHigh, globalDispatchQueueLow);

-----Dispatch Groupasync

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t groupQueue = dispatch_group_create();
    //这五个block并发执行
    dispatch_group_async(groupQueue, queue, ^{NSLog(@"block0");});
    dispatch_group_async(groupQueue, queue, ^{NSLog(@"block1");});
    dispatch_group_async(groupQueue, queue, ^{NSLog(@"block2");});
    dispatch_group_async(groupQueue, queue, ^{NSLog(@"block3");});
    dispatch_group_async(groupQueue, queue, ^{NSLog(@"block4");});
    //结束处理 必定是最后执行的
    dispatch_group_notify(groupQueue, queue, ^{NSLog(@"done");});

dispatch_group中也可使用dispatch_wait函数等待所有处理执行结束

// DISPATCH_TIME_FOREVER 永久等待,group未结束就会一直等待
    dispatch_group_wait(groupQueue, DISPATCH_TIME_FOREVER);
    //如:
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
    long result =  dispatch_group_wait(groupQueue, time);
    if (result == 0) { //若是不为0,就说明虽然过了等待时间,可是某一个group还在处理执行中。
        //属于dispatch group的所有处理执行结束
        NSLog(@"属于dispatch group的所有处理执行结束");
    }else{
        //属于dispatch group的某一个处理还在执行中
        NSLog(@"属于dispatch group的某一个处理还在执行中"); }

还有常常碰到的等待多个异步请求执行完毕方法以下:

    dispatch_group_t serviceGroup = dispatch_group_create();
    //开始第一个请求
    //进入组
    dispatch_group_enter(serviceGroup);
    [self.configService startWithCompletion:^(ConfigResponse *resul ts, NSError* error){
        configError = error;
        //离开组
        dispatch_group_leave(serviceGroup);
    }];
    //开始第二个请求
    //进入组
    dispatch_group_enter(serviceGroup);
    [self.preferenceService startWithCompletion:^(PreferenceRespons e *results, NSError* error){
    
        //离开组
        preferenceError = error;
        dispatch_group_leave(serviceGroup);
    }];
    //当小组里的任务都清空之后 通知主线程
    dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
        // Assess any errors
        NSError *overallError = nil;
        if (configError || preferenceError) {
            // Either make a new error or assign one of them to the
            overall error
            overallError = configError ?: preferenceError;
        }
        // Now call the final completion block
        completion(overallError);
    });

 

 ----dispatch_barrier_async在访问数据库或文件时,使用serial dispatch queue 可避免数据竞争。

    dispatch_queue_t queue = dispatch_queue_create("com.example.gcd.barrier", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{NSLog(@"block0_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block1_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block2_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block3_for_reading");});
    //须要写入处理 -- 当前面执行完再执行dispatch_barrier中的处理,在执行后面的操做
    dispatch_barrier_async(queue, ^{NSLog(@"blockBarrier_for_writing");});
    dispatch_async(queue, ^{NSLog(@"block4_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block5_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block6_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block7_for_reading");});
    dispatch_async(queue, ^{NSLog(@"block8_for_reading");});

         

----dispatch_apply    是dispatch_async和dispatch_group的关联API。

按指定的次数将指定的block追加到指定的dispatch_queue中,并等待所有执行结束。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) {
        NSLog(@"%zu",index);
    });
    NSLog(@"done");

          

有这样的功能,咱们就能够很安全的去循环数组进行元素处理(注:不是按顺序执行)。

    NSArray *array = @[@"00",@"11",@"22",@"33",@"44",@"55",@"66",@"77",@"88",@"99",@"xx"];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(array.count, queue, ^(size_t index) {
        NSLog(@"%zu-%@",index,array[index]);
    });
    NSLog(@"done");

另外,因为dispatch_apply 和 diapatch_sync 函数相同。会等待处理执行结束,所以推荐在dispatch_async函数中非同步的执行dispatch_apply函数

    NSArray *array = @[@"00",@"11",@"22",@"33",@"44",@"55",@"66",@"77",@"88",@"99",@"xx"];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //在global dispatch queue中非同步执行
    dispatch_async(queue, ^{
       //等待dispatch_apply函数中所有处理执行结束
        dispatch_apply(array.count, queue, ^(size_t index) {
           //并列处理包含在NSArray对象的所有对象
            NSLog(@"%zu-%@",index,[array objectAtIndex:index]);
        });
        
        //dispatch_apply函数所有处理执行结束
        dispatch_async(dispatch_get_main_queue(), ^{
           //主线程中更新UI
            NSLog(@"主线程中更新UI");
        });
    });

----dispatch_suspend 挂起中止执行, dispatch_resume恢复执行

----dispatch_semaphore 是持有计数的信号,此计数是变线程编程中计数类型信号。相似于过马路的手旗,能够经过举起手旗,不可经过放下手旗。dispatch_semaphore,计数为0等待,计数大于或等于1时,减去1而不等待。

//建立dispatch_semaphore 计数值初始化为1
    dispatch_semaphore_t  semaphore = dispatch_semaphore_create(1);
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
    long result = dispatch_semaphore_wait(semaphore, time);
    if (result == 0) {//返回为0的时候能够安全的执行能够进行排他控制的处理
        /*
         因为dispatch_semaphore的计数值达到大于等于1
         或者在待机中的指定时间内
         dispatch_semaphore的计数值达到大于等于1
         因此dispatch_semaphore的计数值减去1.
         
         可执行须要进行排他控制处理
         */
    }else{
        /*
         因为dispatch semaphore的计数值为0
         所以在达到指定时间为止待机
         */
    }

实际使用:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //建立dispatch_semaphore 计数值初始化为1
    //保证访问NSMutableArray类对象的线程同时只能有一个
    dispatch_semaphore_t  semaphore = dispatch_semaphore_create(1);
    NSMutableArray *array = [[NSMutableArray alloc]init];
    
    for (int i = 0 ; i < 10000; i ++) {
        dispatch_async(queue, ^{
           /*
            等待dispatch_smaphore
            一直等待,直到dispatch_semaphore的计数值达到大于或等于1
            */
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            /*
             因为dispatch_semaphore的计数值达到大于等于1
             因此将dispatch_semaphore的计数值减去1
             dispatch_semaphore_wait函数执行返回
             
             即此时的dispatch semaphore 恒为0
             
             因为能够访问NSMutableArray类对象的线程只有1个
             所以能够安全的进行更新
             */
            [array addObject:[NSNumber numberWithInt:i]];
            /*
             排他控制处理结束,因此经过dispatch_semaphore_signal函数将dispatch_samaphore的计数值加1.
             
             若是有经过dispatch_semaphore_wait函数等待dispatch_semaphore的计数值增长的线程,就由最早等待的线程执行。
             */
            dispatch_semaphore_signal(semaphore);
        });
    }

在没有serial dispatch queue和dispatch_barrier_async函数那么大粒度且一部分处理须要进行排他处理的状况下,diapatch_semaphore即可以发挥威力。

----Dispatch I/O  

在读取较大文件时,若是将文件分红合适的大小并使用global dispatch queue并列读取的话,会比通常的读取快很多。如今的输入/输出硬件已经能够作到一次使用多个线程更快的并列读取了。能实现这个功能的只有Dispatch I/O 和 Dispatch Data,这个后面更新。

相关文章
相关标签/搜索