实现:等待多个耗时异步任务完成后,执行
方法1:使用wait
代码语言:javascript复制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(@"执行1:%@", [NSThread currentThread]);
sleep(2);
NSLog(@"完成1:%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"执行2:%@", [NSThread currentThread]);
sleep(2);
NSLog(@"完成3:%@", [NSThread currentThread]);
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// 等待所有异步事件执行完毕后继续执行
NSLog(@"是否阻塞主线程"); // 会
方法2:使用notify
代码语言:javascript复制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, dispatch_get_main_queue(), ^{ // 切换到主线程更新UI
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)}
// 都完成后,执行
方法3:使用 enter leave
代码语言:javascript复制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, dispatch_get_main_queue(), ^{ // 切换到主线程更新UI
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)}
// 都完成后,执行
方法4:串行队列
代码语言:javascript复制dispatch_queue_t queue = dispatch_queue_create("com.mo.queue", NULL);
for (int i = 0; i < 3; i ) {
dispatch_async(queue, ^{
NSLog(@"执行%i:%@", i, [NSThread currentThread]);
sleep(1);
NSLog(@"完成%i:%@", i, [NSThread currentThread]);
});
}
dispatch_async(queue, ^{
NSLog(@"以上都执行完毕");
});
信号量semaphore 使用
参考1 参考2
用处1:等待异步回调
代码语言:javascript复制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:控制并发数:
代码语言:javascript复制// 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)
代码语言:javascript复制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实现的:(上一篇中用仅用队列也可实现)
代码语言:javascript复制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 栅栏的使用
代码语言:javascript复制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)}
代码语言:javascript复制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次
代码语言:javascript复制// 例:处理数组
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"); // 会
控制最大并发数
可以使用信号量来控制最大并发数(<0阻塞,>0执行)
代码语言:javascript复制dispatch_queue_t concurrentQueue = dispatch_queue_create("moxiaoyan", DISPATCH_QUEUE_CONCURRENT);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
for (NSInteger i = 0; i < 10; i ) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(concurrentQueue, ^{
NSLog(@"start %ld, %@", (long)i, [NSThread currentThread]);
sleep(1);
NSLog(@"end %ld, %@", (long)i, [NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
});
}
Demo github 地址