Dispatch Queue
Serial Dispatch Queue:依次执行,等待现在执行中处理结束Concurrent Dispatch Queue: 并发执行,不等待现在执行中处理结束
Dispatch Queue 种类
| 1 | // serial dispatch queue | 
dispatch_set_target_queue
dispatch_queue_create 生成的队列都是具有默认有优先级,因此变更队列的优先级使用dispatch_set_target_queue。将不可并行执行的处理追加到多个Serial Dispatch Queue中时,如果使用dispatch_set_target_queue函数指定为某一个Serial Dispatch Queue,则可以防止处理并行执行。
注意:第一个参数如果指定为Main Dispatch Queue和Global Dispatch Queue则不知道会出现什么情况,因此这些均不可指定。
| 1 | dispatch_queue_t serialDispatchQueue = dispatch_queue_create("com.serial", NULL); | 
dispatch_after
使用dispatch_after延时将Block追加到Main Dispatch Queue中处理。
| 1 | dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); | 
Dispatch Group
在追加多个Dispatch Queue中的多个处理全部结束后想执行结束处理,使用Dispatch Group。
| 1 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); | 
dispatch_barrier_async
使用dispatch_barrier_async来避免读写数据库导致的竞争。使用Concurrent Dispatch Queue和dispatch_barrier_async可以实现高效率的数据库访问和文件访问。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15dispatch_queue_t queue = dispatch_queue_create("com.gcd.concureent", DISPATCH_QUEUE_CONCURRENT);
  dispatch_async(queue, ^{NSLog(@"blk0_for_reading");});
  dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
  dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
  dispatch_barrier_async(queue, ^{NSLog(@"blk2_for_writing");});
  dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});
  dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
  // output
  // blk0_for_reading
  // blk1_for_reading
  // blk2_for_reading
  // blk2_for_writing
  // blk3_for_reading
  // blk4_for_reading
dispatch_sync、dispatch_async
dispatch_async:将指定Block非同步追加到指定的Dispatch Queue中,dispatch_async函数不等待Block内的处理结束。dispatch_sync:将指定Block同步追加到指定的Dispatch Queue中,在追加Block结束之前,dispatch_sync函数会一直等待Block内部的处理结束。
在Main Dispatch Queue中谨慎使用dispatch_sync,这样会造成死锁:
Main Dispatch Queue等待Block执行结束,而主线程正在执行这些代码,dispatch_sync又在等待主队列任务结束才将Block添加进queue,所以无法将Block追加到Main Dispatch Queue当中,最终造成死锁。1
2dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{ NSLog(@"Hello!"); });
同行以下也会造成死锁:
| 1 | dispatch_queue_t queue = dispatch_get_main_queue(); | 
| 1 | dispatch_queue_t queue = dispatch_queue_create("com.serialQueue", NULL); | 
dispatch_apply
dispatch_apply是dispatch_sync和Dispatch Group的关联API,该函数指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。
注意:由于dispatch_apply和dispatch_sync相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步地执行dispatch_apply:
| 1 | NSArray *array = @[@0, @1, @2, @3, @4]; | 
dispatch_suspend/dispatch_resume
dispatch_suspend(queue):挂起指定的 queuedispatch_resume(queue):恢复指定的 queue
Disptach Semaphore
提供比 Serial Dispatch Queue 和 dispatch_barrier_async 更加细粒度的控制:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  // 生成 Dispatch Semaphore,并将计数器初始值设定为 1
  // 保证可访问 NSMutableArray 类对象的线程同时只能有1个
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
  NSMutableArray *array = [[NSMutableArray alloc] init];
  for (int i = 0; i < 10000; ++i) {
    dispatch_async(queue, ^{
      // 等待 Dispatch Semaphore,一直等待,直到 Dispatch Semaphore 的计数值达到大于等于 1
      dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
      // Dispatch Semaphore 的计数器大于等于 1,所以将 Dispatch Semaphore 的计数器减去 1,dispatch_semaphore_wait 函数执行返回
      // 由于可访问 NSMutableArray 类对象的线程只有 1 个,因此可安全地进行更新
      [array addObject:[NSNumber numberWithInt:i]];
      
      // 排他控制结束,所以通过 dispatch_semaphore_signal 函数,将 Dispatch Semaphore 的计数器加 1
      // 如果有通过 dispatch_semaphore_wait 函数,等待Dispatch Semaphore的计数值增加的线程,就由最先等待的线程执行
      dispatch_semaphore_signal(semaphore);
    });
  }
dispatch_once
dispatch_once能够在使用多线程环境下,也可保证百分之百安全,这就是单例模式。1
2
3
4static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
   // ...
 });
Dispatch I/O
如果想要提高文件读取速度,可以使用 Dispatch I/O
dispatch_io_read:使用 Global Dispatch Queue开始并列读取。dispatch_io_set_low_water:设定第一次读取的大小(分割大小)。