iOS学习——并发编程GCD

 在iOS中使用的多线程技术有四种,Pthread、NSThread、GCD、NSOperation,但GCD与OP严格来说,应该叫并发编程技术。GCD虽然是用C语言书写,但是苹果对它做了很多封装,让它使用起来及其简单方便,因此在OC开发中应用很广。而OP则是在iOS4.0之后对GCD进行了一次封装,增加了许多用GCD实现比较麻烦的功能,如最大并发数,线程暂停,取消以及依赖添加。

  GCD的使用其实可以拆分成两步,一是队列,二是任务/指令;队列分为串行队列、并发队列、全局队列以及主队列,其中主队列只在主线程上运行,但都遵守FIFO。任务则有异步任务与同步任务。

demo1 :

异步调用会访问线程池调取线程,不开启自线程的情况就是主队列执行异步

//主队列  异步任务
- (void)demo1 {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_async(mainQueue, ^{
        NSLog(@"%s %@",__FUNCTION__,[NSThread currentThread]);
    });

    NSLog(@"结束");
/*
 2017-11-16 19:23:41.644179+0800 iOS学习——GCD[8388:387757] 结束
 2017-11-16 19:23:41.645610+0800 iOS学习——GCD[8388:387757] -[ViewController demo1]_block_invoke <NSThread: 0x604000071200>{number = 1, name = main}
 */
}

demo2:

同步调用任务立刻执行

//主队列  同步任务(如果主线程同步,主线程正在执行demo2这个任务,同步任务又要求主线程执行block内任务,由于线程只有执行完一个任务才能进行下一个,这样资源争夺就会死锁,如果是放在子线程则没有问题)
- (void)demo2 {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"%s",__FUNCTION__ );
        dispatch_sync(mainQueue, ^{
            NSLog(@"%s %@",__FUNCTION__,[NSThread currentThread]);
        });
        NSLog(@"子线程走完 ");
    }];
    NSLog(@"结束");
/*
 2017-11-17 09:50:48.452495+0800 iOS学习——GCD[9829:634367] 结束
 2017-11-17 09:50:48.452541+0800 iOS学习——GCD[9829:635350] -[ViewController demo2]_block_invoke
 2017-11-17 09:50:48.453392+0800 iOS学习——GCD[9829:634367] -[ViewController demo2]_block_invoke_2 <NSThread: 0x60400007eac0>{number = 1, name = main}
 2017-11-17 09:50:48.453540+0800 iOS学习——GCD[9829:635350] 子线程走完
 */
}

demo3:

串行队列同步任务阻塞主线程,由于队列FIFO,所以保持顺序

//串行队列  同步任务 (gcd已经加入arc)
- (void)demo3 {
    dispatch_queue_t serialQueue = dispatch_queue_create("iosSerial", NULL);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(serialQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");
    /*
     2017-11-17 09:52:58.616681+0800 iOS学习——GCD[9854:637007] 第0次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.616871+0800 iOS学习——GCD[9854:637007] 第1次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618652+0800 iOS学习——GCD[9854:637007] 第2次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618805+0800 iOS学习——GCD[9854:637007] 第3次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618944+0800 iOS学习——GCD[9854:637007] 第4次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619485+0800 iOS学习——GCD[9854:637007] 第5次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619606+0800 iOS学习——GCD[9854:637007] 第6次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619715+0800 iOS学习——GCD[9854:637007] 第7次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.702830+0800 iOS学习——GCD[9854:637007] 第8次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.702967+0800 iOS学习——GCD[9854:637007] 第9次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.703120+0800 iOS学习——GCD[9854:637007] 结束
     */
}

demo4:

异步会调用线程池线程,不会阻塞主线程,只有执行完一个任务才能调用,由于串行队列FIFO,所以顺序执行

//串行队列  异步任务
- (void)demo4 {
    dispatch_queue_t serialQueue = dispatch_queue_create("iosSerial", NULL);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");
    /*
     2017-11-17 09:56:50.914235+0800 iOS学习——GCD[9874:639468] 第0次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.914099+0800 iOS学习——GCD[9874:639183] 结束
     2017-11-17 09:56:50.916152+0800 iOS学习——GCD[9874:639468] 第1次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.917729+0800 iOS学习——GCD[9874:639468] 第2次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918009+0800 iOS学习——GCD[9874:639468] 第3次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918256+0800 iOS学习——GCD[9874:639468] 第4次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918381+0800 iOS学习——GCD[9874:639468] 第5次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918494+0800 iOS学习——GCD[9874:639468] 第6次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918600+0800 iOS学习——GCD[9874:639468] 第7次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.951677+0800 iOS学习——GCD[9874:639468] 第8次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.951871+0800 iOS学习——GCD[9874:639468] 第9次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     */
}

demo5:

并发队列,依旧保持队列FIFO特性,但是可以在一个任务未执行完取下一个任务执行,但是由于同步任务阻塞主线程,只有主线程调用任务,所以每次只从队列中取一个任务

//并发队列  同步任务
- (void)demo5 {
    dispatch_queue_t conQueue = dispatch_queue_create("iosConcurrent", DISPATCH_QUEUE_CONCURRENT);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");
    /*
     2017-11-17 10:01:15.328701+0800 iOS学习——GCD[9920:645669] 第0次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.328898+0800 iOS学习——GCD[9920:645669] 第1次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.328987+0800 iOS学习——GCD[9920:645669] 第2次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329083+0800 iOS学习——GCD[9920:645669] 第3次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329206+0800 iOS学习——GCD[9920:645669] 第4次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329473+0800 iOS学习——GCD[9920:645669] 第5次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329584+0800 iOS学习——GCD[9920:645669] 第6次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329786+0800 iOS学习——GCD[9920:645669] 第7次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329917+0800 iOS学习——GCD[9920:645669] 第8次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.330044+0800 iOS学习——GCD[9920:645669] 第9次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.330191+0800 iOS学习——GCD[9920:645669] 结束

     */
}

demo6:

从运行的次数可以看出,并发队列 异步调用的时候,每开启一个线程,都能从队列中取一个任务执行,所以没办法保证执行顺序,而根据线程的number可以判断出,线程从线程池中被拿出来执行完任务后,会回到线程池,等待再次被调用,如果任务未执行完,最先执行完的线程又回到线程池,则将会在此执行。

//并发队列  异步任务
- (void)demo6 {
    dispatch_queue_t conQueue = dispatch_queue_create("iosConcurrent", DISPATCH_QUEUE_CONCURRENT);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(conQueue, ^{
            if (i % 2 == 0) {
                [NSThread sleepForTimeInterval:1.f];//由于执行太快,特阻塞一秒
            }
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");
    /*
     2017-11-17 10:10:02.883676+0800 iOS学习——GCD[9990:654627] 结束
     2017-11-17 10:10:02.883749+0800 iOS学习——GCD[9990:654784] 第1次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f8c0>{number = 3, name = (null)}
     2017-11-17 10:10:02.883773+0800 iOS学习——GCD[9990:654786] 第3次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f900>{number = 4, name = (null)}
     2017-11-17 10:10:02.884475+0800 iOS学习——GCD[9990:655044] 第5次,-[ViewController demo6]_block_invoke <NSThread: 0x60400046efc0>{number = 5, name = (null)}
     2017-11-17 10:10:02.884740+0800 iOS学习——GCD[9990:655045] 第7次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027fcc0>{number = 6, name = (null)}
     2017-11-17 10:10:02.884875+0800 iOS学习——GCD[9990:655044] 第9次,-[ViewController demo6]_block_invoke <NSThread: 0x60400046efc0>{number = 5, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS学习——GCD[9990:654783] 第2次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027fac0>{number = 7, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS学习——GCD[9990:654784] 第6次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f8c0>{number = 3, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS学习——GCD[9990:654786] 第8次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f900>{number = 4, name = (null)}
     2017-11-17 10:10:03.887788+0800 iOS学习——GCD[9990:654785] 第0次,-[ViewController demo6]_block_invoke <NSThread: 0x60400027fc80>{number = 8, name = (null)}
     2017-11-17 10:10:03.887834+0800 iOS学习——GCD[9990:655043] 第4次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f980>{number = 9, name = (null)}
     */
}

demo7、8:

与并发区别在与:1.并发可以命名 2.全局队列在MRC下不需要释放,而并发在MRC下需要主动释放

//全局队列  同步任务
- (void)demo7 {

    //第一个参数代表优先级,

    /* iOS8.0后
    *  - QOS_CLASS_USER_INTERACTIVE
    *  - QOS_CLASS_USER_INITIATED
    *  - QOS_CLASS_DEFAULT
    *  - QOS_CLASS_UTILITY
     *  - QOS_CLASS_BACKGROUND
    */
    /*
     ios 7.0 与8.0比对
     *  - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED  高优先级
     *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT  默认
     *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY   低优先级
     *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND 后台执行,会很慢,需谨慎使用
     */

    /*
     第二个参数是占位参数,暂时没有任何意义,为苹果后续拓展使用
     */
    dispatch_queue_t conQueue = dispatch_get_global_queue(0, 0);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");

}

//全局队列  异步任务
- (void)demo8 {

    dispatch_queue_t conQueue = dispatch_get_global_queue(0, 0);

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"结束");
}

demo9:

同步线程设置依赖关系

//登录   评论  关注 三个操作(登录后才可以评论和关注)  评论或关注后要更新UI
//设置依赖
- (void)demo9 {
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

    dispatch_sync(queue, ^{
        NSLog(@"登录 %@ ",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"评论 %@ ",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"关注 %@ ",[NSThread currentThread]);
    });

    /*
     2017-11-17 11:33:48.563496+0800 iOS学习——GCD[10351:720878] 登录 <NSThread: 0x600000263f80>{number = 1, name = main}
     2017-11-17 11:33:48.563946+0800 iOS学习——GCD[10351:721028] 关注 <NSThread: 0x604000474380>{number = 3, name = (null)}
     2017-11-17 11:33:48.563946+0800 iOS学习——GCD[10351:721030] 评论 <NSThread: 0x604000474080>{number = 5, name = (null)}
     2017-11-17 11:33:48.739571+0800 iOS学习——GCD[10351:720878] 登录 <NSThread: 0x600000263f80>{number = 1, name = main}
     2017-11-17 11:33:48.740086+0800 iOS学习——GCD[10351:721030] 评论 <NSThread: 0x604000474080>{number = 5, name = (null)}
     2017-11-17 11:33:48.740100+0800 iOS学习——GCD[10351:721146] 关注 <NSThread: 0x600000473040>{number = 4, name = (null)}
     */
}

demo10:

由结果可以看出,dispatch_barrier_async可以设置依赖关系,只有之前的代码执行完毕,才执行dispatch_barrier_async内代码,所有代码都是开启子线程执行,不阻塞当前线程;但是它会设置当前内容为同步执行,只有执行dispatch_barrier_async内任务,才能继续执行。如果需要并发执行复数任务作为依赖,然后并发执行复数任务,没有合适dispatch_barrier_async执行条件,这样就必须开启一个空dispatch_barrier_async才行

- (void)demo10 {
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"登录 %@ ",[NSThread currentThread]);
        sleep(1);
    });
    dispatch_barrier_async(queue, ^{
        sleep(5);
        NSLog(@"评论 %@ ",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"关注 %@ ",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"收藏 %@ ",[NSThread currentThread]);
    });
    NSLog(@"结束主线程任务  ");
    /*
     2017-11-17 11:40:15.901540+0800 iOS学习——GCD[10445:729689] 结束主线程任务
     2017-11-17 11:40:15.901692+0800 iOS学习——GCD[10445:729786] 登录 <NSThread: 0x604000471800>{number = 3, name = (null)}
     2017-11-17 11:40:21.910464+0800 iOS学习——GCD[10445:729786] 评论 <NSThread: 0x604000471800>{number = 3, name = (null)}
     2017-11-17 11:40:21.910723+0800 iOS学习——GCD[10445:729798] 收藏 <NSThread: 0x60000026ea00>{number = 4, name = (null)}
     2017-11-17 11:40:22.913477+0800 iOS学习——GCD[10445:729786] 关注 <NSThread: 0x604000471800>{number = 3, name = (null)}
     */
}

demo11:

当group内任务全部执行完毕,就会调用notify通知,所有任务都是异步执行

#pragma mark 调度组

- (void)demo11 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
            NSLog(@"登录 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"评论 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{

            NSLog(@"关注 %@ ",[NSThread currentThread]);

    });
    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主队列,让任务在主线程执行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);

    });
    NSLog(@"结束主线程任务  ");

    /*
     2017-11-17 11:51:20.427599+0800 iOS学习——GCD[10489:740925] 结束主线程任务
     2017-11-17 11:51:20.427726+0800 iOS学习——GCD[10489:741115] 关注 <NSThread: 0x6040004765c0>{number = 4, name = (null)}
     2017-11-17 11:51:20.427726+0800 iOS学习——GCD[10489:741147] 评论 <NSThread: 0x604000475f80>{number = 3, name = (null)}
     2017-11-17 11:51:28.429514+0800 iOS学习——GCD[10489:741114] 登录 <NSThread: 0x604000475f80>{number = 5, name = (null)}
     2017-11-17 11:51:28.429725+0800 iOS学习——GCD[10489:740925] 更新UI <NSThread: 0x60000007f7c0>{number = 1, name = main}
     */
}

demo12、13:

dispatch_group_wait可以阻塞当前线程是假,等待调度组完成,第二个参数为阻塞时间,如果时间大于调度组完成时间,那么调度组完成后,阻塞取消;如果小于调度组完成时间,那么到设定的阻塞时间后,也不再阻塞当前线程,DISPATCH_TIME_FOREVER参数则保证阻塞当前线程直到调度组完成

- (void)demo12 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
        NSLog(@"登录 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"评论 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{

        NSLog(@"关注 %@ ",[NSThread currentThread]);

    });
    //第一个参数: 时间起点
    //第二个参数: 时间长度
    dispatch_group_wait(groupQueue, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC));

    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主队列,让任务在主线程执行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);

    });
    NSLog(@"结束主线程任务  ");
    /*
     2017-11-17 11:53:24.627643+0800 iOS学习——GCD[10507:743414] 评论 <NSThread: 0x60000026ac40>{number = 3, name = (null)}
     2017-11-17 11:53:24.627643+0800 iOS学习——GCD[10507:743373] 关注 <NSThread: 0x60000026ac80>{number = 4, name = (null)}
     2017-11-17 11:53:32.631477+0800 iOS学习——GCD[10507:743374] 登录 <NSThread: 0x604000463300>{number = 5, name = (null)}
     2017-11-17 11:53:32.631708+0800 iOS学习——GCD[10507:743191] 结束主线程任务
     2017-11-17 11:53:32.632605+0800 iOS学习——GCD[10507:743191] 更新UI <NSThread: 0x60400006fb00>{number = 1, name = main}
     */
}
- (void)demo13 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
        NSLog(@"登录 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"评论 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{

        NSLog(@"关注 %@ ",[NSThread currentThread]);

    });

    dispatch_group_wait(groupQueue,  dispatch_time(DISPATCH_TIME_NOW, 4 * NSEC_PER_SEC));

    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主队列,让任务在主线程执行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);

    });
    NSLog(@"结束主线程任务  ");
/*
 2017-11-17 13:52:26.915659+0800 iOS学习——GCD[10810:807557] 评论 <NSThread: 0x604000275640>{number = 3, name = (null)}
 2017-11-17 13:52:26.915659+0800 iOS学习——GCD[10810:807556] 关注 <NSThread: 0x604000275400>{number = 4, name = (null)}
 2017-11-17 13:52:30.916019+0800 iOS学习——GCD[10810:807242] 结束主线程任务
 2017-11-17 13:52:34.919903+0800 iOS学习——GCD[10810:807559] 登录 <NSThread: 0x604000275640>{number = 5, name = (null)}
 2017-11-17 13:52:34.920194+0800 iOS学习——GCD[10810:807242] 更新UI <NSThread: 0x600000065f00>{number = 1, name = main}

 */

}

demo14:

dispatch_group_enter,dispatch_group_leave在项目中必须成对出现,不然会崩溃。如果dispatch_group_async内执行异步线程,notify是无法识别到异步线程是否完成,只会认为执行完dispatch_group_async内任务就通知;但是当用上enter和leave后,只要把enter放在调度组任务创建前,然后leave放在你认为会结束的地方,那么只有等leave执行,notify才会执行

- (void)demo14 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

    dispatch_group_async(groupQueue, queue, ^{

        dispatch_async(queue, ^{
            sleep(8);
            NSLog(@"登录 %@ ",[NSThread currentThread]);
        });
    });

    dispatch_group_enter(groupQueue);
    dispatch_group_async(groupQueue, queue, ^{
        dispatch_async(queue, ^{
            sleep(4);
            NSLog(@"评论 %@ ",[NSThread currentThread]);
            dispatch_group_leave(groupQueue);

        });

    });

    dispatch_group_enter(groupQueue);
    dispatch_group_async(groupQueue, queue, ^{

        NSLog(@"关注 %@ ",[NSThread currentThread]);

    });
    dispatch_group_leave(groupQueue);

    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主队列,让任务在主线程执行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);

    });
    NSLog(@"结束主线程任务  ");
    /*
     2017-11-17 14:05:44.459763+0800 iOS学习——GCD[10883:822533] 结束主线程任务
     2017-11-17 14:05:44.459822+0800 iOS学习——GCD[10883:822914] 关注 <NSThread: 0x60000027f000>{number = 3, name = (null)}
     2017-11-17 14:05:48.462705+0800 iOS学习——GCD[10883:822911] 评论 <NSThread: 0x6040002772c0>{number = 4, name = (null)}
     2017-11-17 14:05:48.462927+0800 iOS学习——GCD[10883:822533] 更新UI <NSThread: 0x604000071640>{number = 1, name = main}
     2017-11-17 14:05:52.460289+0800 iOS学习——GCD[10883:822938] 登录 <NSThread: 0x604000273100>{number = 5, name = (null)}
     */
}
时间: 2024-10-06 02:31:36

iOS学习——并发编程GCD的相关文章

iOS -NSOperation并发编程

http://www.cocoachina.com/game/20151201/14517.html 本文是投稿文章,作者:RyanJIN(简书)对于iOS的并发编程, 用的最普遍的就是GCD了, GCD结合Block可以so easy的实现多线程并发编程. 但如果你看一些诸如AFNetworking, SDWebImage的源码, 你会发现它们使用的都是NSOperation, 纳尼? 难道NSOperation这货更屌? YES, 它确实更屌! Okay, 那我们就先来简单PK下GCD和NS

iOS/MacOS多线程编程GCD

GCD和Block一起,使得iOS多线程编程变得简单优雅许多.如此优雅简单的多线程API真希望C和C++标准中也会有 One of the technologies for starting tasks asynchronously is Grand Central Dispatch (GCD). This technology takes the thread management code you would normally write in your own applications a

并发编程gcd粗暴记忆法

这两天撸了撸多线程,对苹果的这套c语言框架gcd很感兴趣,索性撸下去,发现撸的时候很多概念傻傻分不清楚,鉴于我这跟鱼一样的记忆力,要记忆一下 1.最先接触的概念肯定是进程和线程,what?进程和线程还需要记忆,那么别搞it了,不过还是要阐述一下,进程就像一个个运行着的程序,线程就是程序内部代码的执行路线,如果程序中有多个代码的执行路线,那么就涉及多线程了. 2.操作队列,搞这么个东西很容易让人误解为队列就是线程,但是其实不是,这个玩意只是一个队列(FIFO),队列里面放的是任务,也就是代码. 3

python学习-并发编程(十四)

14.2线程的创建与启动 import threading # 定义一个普通的action函数,该函数准备作为线程执行体 def action(max): for i in range(max): print(threading.current_thread().getName() + " " + str(i)) # 下面是主程序(也就是主线程的执行体) for i in range(100): print(threading.current_thread().getName() +

知其然亦知其所以然--NSOperation并发编程 (转)

本文是投稿文章,作者:RyanJIN(简书)对于iOS的并发编程, 用的最普遍的就是GCD了, GCD结合Block可以so easy的实现多线程并发编程. 但如果你看一些诸如AFNetworking, SDWebImage的源码, 你会发现它们使用的都是NSOperation, 纳尼? 难道NSOperation这货更屌? YES, 它确实更屌! Okay, 那我们就先来简单PK下GCD和NSOperation(当然这里也包括NSOperationQueue). 1). NSOperation

Java并发编程有多难?这几个核心技术你掌握了吗?

本文主要内容索引 1.Java线程 2.线程模型 3.Java线程池 4.Future(各种Future) 5.Fork/Join框架 6.volatile 7.CAS(原子操作) 8.AQS(并发同步框架) 9.synchronized(同步锁) 10.并发队列(阻塞队列) 本文仅分析java并发编程中的若干核心问题,对于上面没有提到但是又和java并发编程有密切关系的技术将会不断添加进来完善文章,本文将长期更新,不断迭代.本文试图从一个更高的视觉来总结Java语言中的并发编程内容,希望阅读完

Java并发编程高阶技术 高性能并发框架源码解析与实战

第1章 课程介绍(Java并发编程进阶课程)什么是Disruptor?它一个高性能的异步处理框架,号称"单线程每秒可处理600W个订单"的神器,本课程目标:彻底精通一个如此优秀的开源框架,面试秒杀面试官.本章会带领小伙伴们先了解课程大纲与重点,然后模拟千万,亿级数据进行压力测试.让大家感性认知到Disruptor的强大.... 第2章 并发编程框架核心讲解本章带大家学习并发编程框架的基本使用与API,并介绍其内部各种组件的原理和运行机制.从而为后面的深入学习打下坚实的基础.如果对Dis

掌握系列之并发编程-1.并发基础

掌握高并发.高可用架构 第二课 并发编程 从本课开始学习并发编程的内容.主要介绍并发编程的基础知识.锁.内存模型.线程池.各种并发容器的使用. 第一节 并发基础 并发编程 并发基础 进程 线程 线程通信 系统.包括操作系统的运行是以CPU为核心的,各种数据操作都是在CPU中进行的.所以要学习并发编程,必须要搞清楚和CPU的关系. CPU简介 经常说CPU是4核8线程的,这个的意思是4个物理核心,每个物理核心虚拟出2个虚拟核心,也就是8个虚拟核心 .每个虚拟核心在一个时刻只能运行一个线程. 进程和

【并发编程】并发编程中你需要知道的基础概念

本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 多线程是Java编程中一块非常重要的内容,其中涉及到很多概念.这些概念我们平时经常挂在嘴上,但是真的要让你介绍下这些概念,你可能还真的讲不清楚.这篇博客就总结下多线程编程中经常用到的概念,理解这些概念能帮助我们更好地掌握多线程编程. 进程(Process)与线程(Thread) 进程和线程是最常提到的概念了.在linux中,线程与进程最大的区别就是是否共