iOS_多线程二:GCD:notify、enter leave、semaphore、barrier、diapatch_apply等的使用

实现:等待多个耗时异步任务完成后,执行

方法1:使用notify

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
  NSLog(@"执行1:%@", [NSThread currentThread]);
  sleep(2);
  NSLog(@"完成1:%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
  NSLog(@"执行2:%@", [NSThread currentThread]);
  sleep(4);
  NSLog(@"完成2:%@", [NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
  NSLog(@"都完成后,执行");
});
NSLog(@"是否阻塞主线程"); // 不会
// 执行结果:
// 是否阻塞主线程
// 执行2:<NSThread: 0x60000142efc0>{number = 5, name = (null)}
// 执行1:<NSThread: 0x600001425440>{number = 3, name = (null)}
// 完成1:<NSThread: 0x600001425440>{number = 3, name = (null)}
// 完成2:<NSThread: 0x60000142efc0>{number = 5, name = (null)}
// 都完成后,执行

方法2:使用 enter leave

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//dispatch_queue_create("moxiaoyan", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_enter(group);
dispatch_async(queue, ^{
  NSLog(@"执行1:%@", [NSThread currentThread]);
  sleep(3);
  NSLog(@"完成1:%@", [NSThread currentThread]);
  dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
  NSLog(@"执行2:%@", [NSThread currentThread]);
  sleep(4);
  NSLog(@"完成2:%@", [NSThread currentThread]);
  dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
  NSLog(@"都完成后,执行");
});
NSLog(@"是否阻塞主线程"); // 不会
// 执行结果:
// 是否阻塞主线程
// 执行2:<NSThread: 0x60000334cfc0>{number = 5, name = (null)}
// 执行1:<NSThread: 0x600003344c00>{number = 6, name = (null)}
// 完成1:<NSThread: 0x600003344c00>{number = 6, name = (null)}
// 完成2:<NSThread: 0x60000334cfc0>{number = 5, name = (null)}
// 都完成后,执行

信号量semaphore 使用

参考1 参考2

用处1:等待异步回调

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 传入的值必须>=0,否则返回NULL
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // 如果>0:则不会等待
dispatch_async(queue, ^{
  NSLog(@"执行:%@", [NSThread currentThread]);
  sleep(2);
  NSLog(@"完成:%@", [NSThread currentThread]);
  dispatch_semaphore_signal(semaphore); // semaphore+1
});
NSLog(@"wait");
// 会阻塞当前线程(这里是主线程)
// semaphore为0,会等待timeout
// 等待期间 semaphore>0 or timeout 会解除阻塞继续执行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // semaphore-1
// 设置当前时间延迟几秒: dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 10); 
NSLog(@"是否阻塞主线程"); // 会
// 执行结果:
// wait
// 执行:<NSThread: 0x60000203ca40>{number = 5, name = (null)}
// 完成:<NSThread: 0x60000203ca40>{number = 5, name = (null)}
// 是否阻塞主线程

用处2:控制并发数:

// create的value表示,最多几个资源可访问 (可以测试一下:1~3)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(quene, ^{
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  NSLog(@"任务1 执行");
  sleep(1);
  NSLog(@"任务1 完成");
  dispatch_semaphore_signal(semaphore);
});
dispatch_async(quene, ^{
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  NSLog(@"任务2 执行");
  sleep(2);
  NSLog(@"任务2 完成");
  dispatch_semaphore_signal(semaphore);
});
dispatch_async(quene, ^{
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  NSLog(@"任务3 执行");
  sleep(1);
  NSLog(@"任务3 完成");
  dispatch_semaphore_signal(semaphore);
});
NSLog(@"是否阻塞主线程"); // 不会
// 执行结果:
// 是否阻塞主线程
// 任务1 执行
// 任务2 执行
// 任务1 完成
// 任务3 执行
// 任务2 完成
// 任务3 完成

由于设定的信号值为2,先执行两个线程,等执行完一个,才会继续执行下一个,保证同一时间执行的线程数不超过2

用处3:为线程加锁:(性能远高于@synchronized,仅次于OSSpinLock)

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); // 第1个不会wait
for (int i = 0; i < 20; i++) {
 dispatch_async(queue, ^{
  // 相当于加锁
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 使semaphore-1
  sleep(2);
  NSLog(@"i = %d semaphore = %@", i, semaphore);
  // 相当于解锁
  dispatch_semaphore_signal(semaphore); // 使semaphore+1
 });
}
NSLog(@"是否阻塞主线程"); // 不会
// 当第一个异步循环走到wait时,因为semaphore>0,所以会-1,继续执行: signal+1
// 如果下一个循环在上一个循环结束前开始, 因为 semaphore>0, 所以会wait,直到signal+1
// 保证了log循序输出

实现多个异步顺序执行:

这里是用group+semaphore实现的:(上一篇中用仅用队列也可实现)

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_async(group, queue, ^{
    NSLog(@"执行1:%@", [NSThread currentThread]);
    sleep(2);
    NSLog(@"完成1:%@", [NSThread currentThread]);
    dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
    NSLog(@"执行2:%@", [NSThread currentThread]);
    sleep(3);
    NSLog(@"完成2:%@", [NSThread currentThread]);
    dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
    NSLog(@"执行3:%@", [NSThread currentThread]);
    sleep(1);
    NSLog(@"完成3:%@", [NSThread currentThread]);
    dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"是否阻塞主线程"); // 会
// 执行结果:
// 执行1:<NSThread: 0x600000607fc0>{number = 4, name = (null)}
// 完成1:<NSThread: 0x600000607fc0>{number = 4, name = (null)}
// 执行2:<NSThread: 0x600000607fc0>{number = 4, name = (null)}
// 完成2:<NSThread: 0x600000607fc0>{number = 4, name = (null)}
// 执行3:<NSThread: 0x600000650000>{number = 8, name = (null)}
// 是否阻塞主线程

barrier 栅栏的使用

dispatch_queue_t queue = dispatch_queue_create("moxiaoyan", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
  NSLog(@"执行1:%@", [NSThread currentThread]);
  sleep(2);
  NSLog(@"完成1:%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
  NSLog(@"执行2:%@", [NSThread currentThread]);
  sleep(3);
  NSLog(@"完成2:%@", [NSThread currentThread]);
});
dispatch_barrier_sync(queue, ^{
  NSLog(@"栅栏");
});
dispatch_async(queue, ^{
  NSLog(@"执行3:%@", [NSThread currentThread]);
  sleep(1);
  NSLog(@"完成3:%@", [NSThread currentThread]);
});
NSLog(@"是否阻塞主线程"); // 会
// 执行结果
// 执行1:<NSThread: 0x6000016433c0>{number = 5, name = (null)}
// 执行2:<NSThread: 0x60000167cbc0>{number = 6, name = (null)}
// 完成1:<NSThread: 0x6000016433c0>{number = 5, name = (null)}
// 完成2:<NSThread: 0x60000167cbc0>{number = 6, name = (null)}
// 栅栏
// 是否阻塞主线程
// 执行3:<NSThread: 0x60000167cbc0>{number = 6, name = (null)}
// 完成3:<NSThread: 0x60000167cbc0>{number = 6, name = (null)}
dispatch_queue_t queue = dispatch_queue_create("moxiaoyan", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
  NSLog(@"执行1:%@", [NSThread currentThread]);
  sleep(2);
  NSLog(@"完成1:%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
  NSLog(@"执行2:%@", [NSThread currentThread]);
  sleep(3);
  NSLog(@"完成2:%@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
  NSLog(@"栅栏");
});
dispatch_async(queue, ^{
  NSLog(@"执行3:%@", [NSThread currentThread]);
  sleep(1);
  NSLog(@"完成3:%@", [NSThread currentThread]);
});
NSLog(@"是否阻塞主线程"); // 不会
// 执行结果
// 是否阻塞主线程
// 执行1:<NSThread: 0x600002810bc0>{number = 3, name = (null)}
// 执行2:<NSThread: 0x60000281ad40>{number = 5, name = (null)}
// 完成1:<NSThread: 0x600002810bc0>{number = 3, name = (null)}
// 完成2:<NSThread: 0x60000281ad40>{number = 5, name = (null)}
// 栅栏
// 执行3:<NSThread: 0x60000281ad40>{number = 5, name = (null)}
// 完成3:<NSThread: 0x60000281ad40>{number = 5, name = (null)}

diapatch_apply使用:

往队列中添加任务,任务会重复执行n次

// 例:处理数组
NSArray *array = @[@"a", @"b", @"c", @"d"];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(array.count, queue, ^(size_t index) { // index倒序
  NSLog(@"index:%zu %@", index, array[index]);
});
NSLog(@"是否阻塞主线程 dispatch_apply"); // 会

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章