zoukankan      html  css  js  c++  java
  • 同步异步执行问题

    多个网络请求同时执行,等所有网络请求完成,再统一做其他操作,我们可能会想到dispatch_group_async、dispatch_group_notify结合使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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(@"任务一完成");
        });
         
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务二完成");
        });
         
        dispatch_group_async(group, queue, ^{
            NSLog(@"任务三完成");
        });
        //在分组的所有任务完成后触发
        dispatch_group_notify(group, queue, ^{
            NSLog(@"所有任务完成");
        });

    或者使用栅栏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (void)barrier {
    //    dispatch_queue_t queue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_CONCURRENT);
        dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
         
        dispatch_async(queue, ^{
            NSLog(@"任务1-1完成");
        });
        dispatch_async(queue, ^{
            NSLog(@"任务1-2完成");
        });
         
        dispatch_async(queue, ^{
            NSLog(@"任务1-3完成");
        });
         
        dispatch_barrier_async(queue, ^{
            NSLog(@"以上任务都完成 dispatch_barrie完成");
        });
    }

    比如上述写法,内部执行的是同步操作没有问题,如果以上三个任务都是异步的,比如是网络请求,那么就达不到我们想要的效果。因为异步,请求没有回来,dispatch_group_notify或者dispatch_barrier_async已经执行了。

    我们可以采用信号量或者dispatch_group_enter、dispatch_group_leave实现。

    核心思想:将异步变成同步

    下述描述了常见场景下的代码实现:包括顺序执行和同时执行异步操作

    顺序执行 :

    方式 : 信号量semaphore (必须放在子线程 dispatch_semaphore_wait会卡死主线程) (例:1执行完了执行2)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    - (void)serialBySemaphore {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
     
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
     
            [self requestOneWithSuccessBlock:^{
                dispatch_semaphore_signal(semaphore);
            }];
     
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
     
            [self requestTwoWithBlock:^{
            }];
        });
    }
    执行到dispatch_semaphore_wait时,由于信号量为0,进行等待,请求1完成后调用dispatch_semaphore_signal ,信号量不再为0,接着执行请求2

    方式: GCD dispatch_group_enter/leave (例: 1, 2 同时执行 执行完了再执行3)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    -(void)serialByGroupWait {
         
        dispatch_group_t group = dispatch_group_create();
         
        dispatch_group_enter(group);
        [self requestOneWithSuccessBlock:^{
            dispatch_group_leave(group);
        }];
         
        dispatch_group_enter(group);
        [self requestTwoWithBlock:^{
            dispatch_group_leave(group);
        }];
      // 1  2同时执行
         
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);// 1 2 执行完 下面才会执行
         
        dispatch_group_enter(group);
        [self requestThreeWithBlock:^{
            dispatch_group_leave(group);
        }];
         
      // 1 2 3 都完成 才会执行
        dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"all request  done!");
        });
    }
    执行到dispatch_group_wait时,由于enter数不等于leave数,进行等待,请求1,2都完成后调用dispatch_group_leave ,enter数等于leave数,接着执行请求3。 请求1,2,3都执行后,dispatch_group_notify执行

    方式三:回调中执行
    1
    2
    3
    4
    5
    6
    - (void) serialByCallBack {
        [self requestOneWithSuccessBlock:^{
            [self requestTwoWithBlock:^{
            }];
        }];
    }
    low方法,请求一多,嵌套恶心


    同时执行 :

    方式:信号量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    -(void)concurrentBySemaphore {
     dispatch_group_t group = dispatch_group_create();
         
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            [self requestOneWithSuccessBlock:^{
                dispatch_semaphore_signal(sema);
            }];
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
         
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            [self requestTwoWithSuccessBlock:^{
                dispatch_semaphore_signal(sema);
            }];
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"全部搞完了");
        });
    }

    方式:dispatch_group_enter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    -(void)concurrentByGroup {
         
        dispatch_group_t group = dispatch_group_create();
         
        dispatch_group_enter(group);
        [self requestOneWithSuccessBlock:^{
            dispatch_group_leave(group);
        }];
         
        dispatch_group_enter(group);
        [self requestTwoWithBlock:^{
            dispatch_group_leave(group);
        }];
         
      // 1 2  都完成 才会执行
        dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"all request  done!");
        });
    }


    扩充:循环请求情况 顺序请求/同时请求


    *模拟循环网络请求 同时进行 统一回调 (GCD + 信号量方式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (void)concurrentTest1 {
        dispatch_group_t group = dispatch_group_create();
        for (int i = 0 ; i < 5; i++) {
            dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                dispatch_semaphore_t sema = dispatch_semaphore_create(0);
                 // 模拟请求 ↓
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    sleep(3);
                    NSLog(@"任务%d完成",i);
                     dispatch_semaphore_signal(sema);
                });
                 // 模拟请求 上
                dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            });
        }
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"全部搞完了");
        });
    }

    执行结果:

    1
    2
    3
    4
    5
    6
    00:21:38.413337+0800 mmmm[4595:182516] 任务1完成
    00:21:38.413337+0800 mmmm[4595:182518] 任务3完成
    00:21:38.413358+0800 mmmm[4595:182517] 任务2完成
    00:21:38.413358+0800 mmmm[4595:182515] 任务0完成
    00:21:38.413447+0800 mmmm[4595:182519] 任务4完成
    00:21:38.413843+0800 mmmm[4595:182428] 全部搞完了



    *模拟循环网络请求 同时进行 统一回调 (GCD + group enter/leave 方式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    - (void)concurrentTest2 {
        dispatch_group_t group = dispatch_group_create();
        for (int i = 0 ; i < 5; i++) {
            dispatch_group_enter(group);
              // 模拟请求 ↓
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(3);
                NSLog(@"任务%d完成",i);
                dispatch_group_leave(group);
            });
              // 模拟请求 ↑
        }
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"全部搞完了");
        });
    }

    执行结果:

    1
    2
    3
    4
    5
    6
    2019-04-12 00:26:38.607040+0800 mmmm[4641:184613] 任务0完成
    2019-04-12 00:26:38.607043+0800 mmmm[4641:184612] 任务2完成
    2019-04-12 00:26:38.607059+0800 mmmm[4641:184611] 任务3完成
    2019-04-12 00:26:38.607067+0800 mmmm[4641:184610] 任务1完成
    2019-04-12 00:26:38.607088+0800 mmmm[4641:184625] 任务4完成
    2019-04-12 00:26:38.607353+0800 mmmm[4641:184559] 全部搞完了

    *模拟循环网络请求 顺序进行 (GCD + 信号量方式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    - (void)serialTest1 {
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i = 0 ; i < 5; i++) {
                NSLog(@"开始%d",i);
                // 模拟请求 ↓
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    sleep(3);
                    NSLog(@"任务%d完成",i);
                    dispatch_semaphore_signal(sema);
                });
                // 模拟请求 上
               dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            }
             
           NSLog(@"全部搞完了");
        });
    }

    执行结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    2019-04-12 01:31:45.291818+0800 mmmm[5417:215007] 开始0
    2019-04-12 01:31:48.297299+0800 mmmm[5417:215008] 任务0完成
    2019-04-12 01:31:48.297746+0800 mmmm[5417:215007] 开始1
    2019-04-12 01:31:51.298592+0800 mmmm[5417:215008] 任务1完成
    2019-04-12 01:31:51.298841+0800 mmmm[5417:215007] 开始2
    2019-04-12 01:31:54.300477+0800 mmmm[5417:215008] 任务2完成
    2019-04-12 01:31:54.300908+0800 mmmm[5417:215007] 开始3
    2019-04-12 01:31:57.305197+0800 mmmm[5417:215008] 任务3完成
    2019-04-12 01:31:57.305623+0800 mmmm[5417:215007] 开始4
    2019-04-12 01:32:00.311062+0800 mmmm[5417:215008] 任务4完成
    2019-04-12 01:32:00.311407+0800 mmmm[5417:215007] 全部搞完了

    *模拟循环网络请求 顺序进行 (GCD + group enter/leave 方式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    - (void)serialTest2 {
        dispatch_group_t group = dispatch_group_create();
        for (int i = 0 ; i < 5; i++) {
            dispatch_group_enter(group);
            // 模拟请求 ↓
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(6 - i);
                NSLog(@"任务%d完成",i);
                dispatch_group_leave(group);
            });
            // 模拟请求 ↑
            dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 顺序执行与同步执行的不同点
        }
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"全部搞完了");
        });
    }

    执行结果

    1
    2
    3
    4
    5
    6
    2019-04-12 00:33:46.020376+0800 mmmm[4748:188409] 任务0完成
    2019-04-12 00:33:51.021098+0800 mmmm[4748:188409] 任务1完成
    2019-04-12 00:33:55.022758+0800 mmmm[4748:188409] 任务2完成
    2019-04-12 00:33:58.023783+0800 mmmm[4748:188409] 任务3完成
    2019-04-12 00:34:00.027929+0800 mmmm[4748:188409] 任务4完成
    2019-04-12 00:34:00.028444+0800 mmmm[4748:188374] 全部搞完了
  • 相关阅读:
    cf C. Vasya and Robot
    zoj 3805 Machine
    cf B. Vasya and Public Transport
    cf D. Queue
    cf C. Find Maximum
    cf B. Two Heaps
    cf C. Jeff and Rounding
    cf B. Jeff and Periods
    cf A. Jeff and Digits
    I Think I Need a Houseboat
  • 原文地址:https://www.cnblogs.com/Mr-zyh/p/12191759.html
Copyright © 2011-2022 走看看