iOS经典面试题之分析GCD的dispatch_group任务执行问题

① dispatch_group 异步执行任务
  • 现有以下调度组 dispatch_group 执行多个任务,将 dispatch_group_notify 放在调度组异步执行任务,那么它们的任务执行顺序是怎么样的呢?
	dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        sleep(1);
        NSLog(@"任务1");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        NSLog(@"任务2");
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    
    
        NSLog(@"任务3:主线程更新UI");
    });
    NSLog(@"任务4:主线程正在执行");
  • 执行程序,结果如下:
	任务4:主线程正在执行
	任务2
	任务1
	任务3:主线程更新UI
  • 分析:
    • dispatch_group 执行任务开始时, 程序由上到下执行任务1、任务2、任务3、任务4;
    • 由于任务4没有在调度组中,因此优先执行;
    • 然后有两个调度组异步执行任务1和任务2,最后再通知主线程执行任务3;
    • 由于第一个任务1中线程sleep(1),因此任务2会比任务1优先完成;
    • 最后再通知主线程执行任务3,更新UI。
② 如果将 dispatch_group_notify 移动到最前面,能否执行?执行结果是怎样的呢?
  • 代码修改如下:
	dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    
    
        NSLog(@"任务3:主线程更新UI");
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        sleep(1);
        NSLog(@"任务1");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        NSLog(@"任务2");
        dispatch_group_leave(group);
    });
    NSLog(@"任务4:主线程正在执行");
  • 执行结果如下:
	任务4:主线程正在执行
	任务2
	任务3:主线程更新UI
	任务1
  • 可以看到程序能正常执行,但是只要有 enter-leave 成对匹配,notify 就会执行,不会等两个调度组都执行完毕,即只要 enter-leave 成对程序就可以执行。
③ 再加一个enter,即 enter:wait 是 3:2,能否执行 notify ?
  • 修改代码如下:
	dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        sleep(1);
        NSLog(@"任务1");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        NSLog(@"任务2");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    
    
        NSLog(@"任务3:主线程更新UI");
    });
    NSLog(@"任务4:主线程正在执行");
  • 执行结果如下:
	任务4:主线程正在执行
	任务2
	任务1
  • 可以看到,程序不能正常执行完毕,会一直等待,这是因为等待 leave 的执行,最后才会执行 notify。
  • 如果 dispatch_group_enter 比 dispatch_group_leave 多,由于 value 不等于 dsema_orig 不会走到唤醒逻辑, dispatch_group_notify 中的任务无法执行或者 dispatch_group_wait 收不到信号而卡住线程。
④ 如果是 enter:wait 是 2:3,能否执行 notify ?
  • 修改代码如下:
	dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        sleep(1);
        NSLog(@"任务1");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
    
    
        NSLog(@"任务2");
        dispatch_group_leave(group);
    });
    dispatch_group_leave(group);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    
    
        NSLog(@"任务3:主线程更新UI");
    });
    NSLog(@"任务4:主线程正在执行");
  • 执行程序之后,可以看到程序会延迟崩溃在任务1的dispatch_group_leave(group),这是因为 enter-leave 没有成对匹配,dispatch_group 没有 enter,却需要 leave 导致 value 不等于 dsema_orig 不会走到唤醒逻辑。

猜你喜欢

转载自blog.csdn.net/Forever_wj/article/details/115451884