GCD的介绍

项目开发中我们经常用到异步,同步,串行执行,并行执行,主线程,后台线程.

1.异步vs同步

最简单的说,执行队列里面的block以哪种方式:

  • dispatch_async - 异步执行的block,不会阻塞他下面的代码执行(如你在异步执行的block里面sleep(10),不会影响其他代码的继续执行)
  • dispatch_sync - 同步执行的block,直到block里面的代码执行完了才会继续执行他下面的代码(主线程注意会造成死锁)
  • 拷贝以下代码,在xcode运行查看输出结果;然后修改dispatch_async为dispatch_sync再查看

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    NSLog(@"---begin----");
    dispatch_async(queue, ^{
    		sleep(7);
    		NSLog(@"----1---");
    });
        
    dispatch_async(queue, ^{
    		sleep(2);
    		NSLog(@"-----2-----");
    });
    NSLog(@"---end----");

    2.串行vs并行

    是指队列里面block排列方式,与异步同步是两个概念:
    				
    dispatch_queue_t queue2 = dispatch_get_main_queue(); 获得的queue2是主线程上的一个串行队列,所有放入到queue2里面的任务是按顺序执行
    
    dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 获取queue1是后台线程上的一个并行队列,所有放入到queue1里面的任务并列表执行不分先后顺序
    
    dispatch_queue_t queue = dispatch_queue_create("my-queue", DISPATCH_QUEUE_SERIAL); 自定义一个后台串行队列;请注意最后一个参数,不是NULL。DISPATCH_QUEUE_SERIAL这个参数大家可以看一下它的宏定义就是一个NULL。建议规范写法
    
    dispatch_queue_t queue = dispatch_queue_create("my-queue", DISPATCH_QUEUE_CONCURRENT);自定义一个后台并行队列;请注意最后一个参数,不是NULL。DISPATCH_QUEUE_CONCURRENT表示队列是并行的.

    3.一些误区

  • dispatch_queue_t queue1 = dispatch_queue_create("my-queue-text", DISPATCH_QUEUE_SERIAL);
  • dispatch_queue_t queue2 = dispatch_queue_create("my-queue-text", DISPATCH_QUEUE_SERIAL);
  • 虽然两个queue的标识符都是my-queue-text,而且都为串行的,但实际上这是两个不同的队列。他们两的工作队列互不影响。如果你想要保证所有任务串,最好申明一个全局的queue出来。

    4.dispatch_after

    开发中经常有一些延迟几秒后的操作我们会用dispatch_after。after几秒指的是将一个Block在特定的延时以后,加入到指定的队列中,不是在特定的时间后立即运行!。(重要的话说三遍)

    dispatch_queue_t queue = dispatch_queue_create("my-fifo-queue", DISPATCH_QUEUE_SERIAL); //一个后台串行队列
    NSLog(@"------begin-----");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
    	  NSLog(@"----after 2s----");
    });
    
    dispatch_async(queue, ^{
    	  sleep(5);
    	  NSLog(@"-----3-----");
    });
    				
    NSLog(@"------end-----");

    以上代码解析:
    1.在后台创建一个串行队列
    2.在2秒后插入一个block(此block的功能只打印after 2s)
    3.在队列中插入另一个block(此block线程睡5s后打印3)

    输出结果:begin,end,3,after 2s;
    因为是一个异步操作,所以执行的block不会阻塞后面代码的打印(输入出begin,end);因为dispatch_after是延迟2s后才把block插入到队列中,所以队列是第一个插入的是“打印3”;但是”打印3“在队列里执行的时候睡了5s,只有等到7s的时候才会把”after2s“的block插入并执行。

    4.有意思的栅栏dispatch_barrier_async

    一个dispatch barrier 允许在一个并发(只有并发才有意义)队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作

     dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"dispatch_async1");
        });
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"dispatch_async2");
        });
        dispatch_barrier_async(queue, ^{
            NSLog(@"dispatch_barrier_async");
            [NSThread sleepForTimeInterval:0.5];
            
        });
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"dispatch_async3");
        });
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"dispatch_async4");
        });
    前面在异步的并行队列中插入两入block,中间用dispatch_barrier_async拦了一下,后面又插入两入block。前两个谁快谁先执行(并行);当前两个执行完,再执行dispatch_barrier_async,最后两在dispatch_barrier_async之后并行执行。

    5.用信息号做多线程锁

    上锁的方式有很多种,synchronized, nslock,POSIX,OSSpinLock等,dispatch_semaphore_t性能也不错

    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    /*** 
    	DISPATCH_TIME_FOREVER:等待时间
    	wait之后信号量-1,为0
    	*/
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //do something,需要线程安全的
    /**
    *  发送一个信号通知,这时候信号量+1,为1
    */
    dispatch_semaphore_signal(semaphore);