iOS 多线程系列 -- GCD全解二(常用方法)

2018-04-12  本文已影响91人  shannoon

iOS 多线程系列 -- 基础概述
iOS 多线程系列 -- pthread
iOS 多线程系列 -- NSThread
iOS 多线程系列 -- GCD全解一(基础)
iOS 多线程系列 -- GCD全解二(常用方法)
iOS 多线程系列 -- GCD全解三(进阶)
iOS 多线程系列 -- NSOperation
测试Demo的GitHub地址

3. GCD常用方法

3.1 Dispatch Group

Dispatch Group 可以让我们很方便的控制多线程中任务执行顺序。假设这样一种需求,有三个任务OA/OB/OC,我们想让OC在OAOB执行完毕在执行,有几种实现方式?方式有很多,详细看下面总结,其中一种方式我们就可以用Dispatch Group实现。

常用方法:
    dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        for (int i = 0; i<10; i++) {
            NSLog(@"---group1--%d---%@",i,[NSThread currentThread]);
        }
    });
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
    //任务OA
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
    //任务OB
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //任务OC
});
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)); 
- (void)group
{
    NSLog(@"---group-begin---%@",[NSThread currentThread]);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{// 异步添加任务到全局并发队列,并关联到调度组
        for (int i = 0; i<2; i++) {
            NSLog(@"---group1--%d---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_group_async(group, dispatch_get_main_queue(), ^{// 异步添加任务到主队列,并关联到调度组
        for (int i = 0; i<2; i++) {
            NSLog(@"---group2--%d---%@",i,[NSThread currentThread]);
        }
    });
    NSLog(@"---group middle %@",[NSThread currentThread]);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // group中的任务都执行完毕后,才回执行这个block
        NSLog(@"---dispatch_group_notify---%@",[NSThread currentThread]);
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"---group3-----%@",[NSThread currentThread]);
        });
        NSLog(@"---dispatch_group_notify middle %@",[NSThread currentThread]);
        dispatch_group_async(group, dispatch_get_main_queue(), ^{
            NSLog(@"---group4----%@",[NSThread currentThread]);
        });
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"---second dispatch_group_notify---%@",[NSThread currentThread]);
        });
    });
    NSLog(@"---before dispatch_group_wait %@",[NSThread currentThread]);
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)); // 同步函数,会阻塞当前线程,只要超时或者group任务完成,返回0表示任务完全执行完毕,非0表示超时
    NSLog(@"---group-end---%@",[NSThread currentThread]);
}
2017-06-29 10:38:15.572 Test - 多线程[21587:754475] ---group-begin---<NSThread: 0x60000007d200>{number = 1, name = main}
 2017-06-29 10:38:15.573 Test - 多线程[21587:754568] ---group1--0---<NSThread: 0x6000002742c0>{number = 3, name = (null)}
 2017-06-29 10:38:15.573 Test - 多线程[21587:754475] ---group middle <NSThread: 0x60000007d200>{number = 1, name = main}  //①
 2017-06-29 10:38:15.573 Test - 多线程[21587:754568] ---group1--1---<NSThread: 0x6000002742c0>{number = 3, name = (null)}  //②
 2017-06-29 10:38:15.573 Test - 多线程[21587:754475] ---before dispatch_group_wait <NSThread: 0x60000007d200>{number = 1, name = main} //③
 2017-06-29 10:38:20.575 Test - 多线程[21587:754475] ---group-end---<NSThread: 0x60000007d200>{number = 1, name = main} //④
 2017-06-29 10:38:20.576 Test - 多线程[21587:754475] ---group2--0---<NSThread: 0x60000007d200>{number = 1, name = main}
 2017-06-29 10:38:20.576 Test - 多线程[21587:754475] ---group2--1---<NSThread: 0x60000007d200>{number = 1, name = main} //⑤
 2017-06-29 10:38:20.577 Test - 多线程[21587:754475] ---dispatch_group_notify---<NSThread: 0x60000007d200>{number = 1, name = main} //⑥
 2017-06-29 10:38:20.577 Test - 多线程[21587:754475] ---dispatch_group_notify middle <NSThread: 0x60000007d200>{number = 1, name = main}
 2017-06-29 10:38:20.577 Test - 多线程[21587:754568] ---group3-----<NSThread: 0x6000002742c0>{number = 3, name = (null)}
 2017-06-29 10:38:20.578 Test - 多线程[21587:754475] ---group4----<NSThread: 0x60000007d200>{number = 1, name = main}
 2017-06-29 10:38:20.578 Test - 多线程[21587:754475] ---second dispatch_group_notify---<NSThread: 0x60000007d200>{number = 1, name = main} //⑦

3.2 栅栏

dispatch_barrier_sync
void dispatch_barrier_sync(dispatch_queue_t queue,
        DISPATCH_NOESCAPE dispatch_block_t block);
 NSLog(@"barrierSync begin");
dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
    
dispatch_async(queue, ^{
    NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"----2-----%@", [NSThread currentThread]);
});
NSLog(@"before dispatch_barrier_sync");
dispatch_barrier_sync(queue, ^{
    NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
NSLog(@"after dispatch_barrier_sync");

dispatch_async(queue, ^{
    NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"----4-----%@", [NSThread currentThread]);
});
NSLog(@"barrierSync end");
2017-06-29 12:28:15.355 Test - 多线程[22813:835755] barrierSync begin //①
 2017-06-29 12:28:15.355 Test - 多线程[22813:835755] before dispatch_barrier_sync //②
 2017-06-29 12:28:15.355 Test - 多线程[22813:835803] ----2-----<NSThread: 0x6000002692c0>{number = 4, name = (null)} //③
 2017-06-29 12:28:15.355 Test - 多线程[22813:835805] ----1-----<NSThread: 0x608000260bc0>{number = 3, name = (null)} //④
 2017-06-29 12:28:15.356 Test - 多线程[22813:835755] ----barrier-----<NSThread: 0x600000071880>{number = 1, name = main} //⑤
 2017-06-29 12:28:15.356 Test - 多线程[22813:835755] after dispatch_barrier_sync //⑥
 2017-06-29 12:28:15.356 Test - 多线程[22813:835755] barrierSync end //⑦
 2017-06-29 12:28:15.356 Test - 多线程[22813:835805] ----3-----<NSThread: 0x608000260bc0>{number = 3, name = (null)} //⑧
 2017-06-29 12:28:15.356 Test - 多线程[22813:835803] ----4-----<NSThread: 0x6000002692c0>{number = 4, name = (null)} //⑨
dispatch_barrier_async,基本和dispatch_barrier_sync类似的功能,区别在于:
NSLog(@"barrierAsync begin");
dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
    
dispatch_async(queue, ^{
    NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"----2-----%@", [NSThread currentThread]);
});
NSLog(@"before dispatch_barrier_async");
dispatch_barrier_async(queue, ^{
    NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
NSLog(@"after dispatch_barrier_async");
    
dispatch_async(queue, ^{
    NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"----4-----%@", [NSThread currentThread]);
});
NSLog(@"barrierAsync end");
2017-06-29 12:29:32.048 Test - 多线程[22813:835755] barrierAsync begin //①
 2017-06-29 12:29:32.049 Test - 多线程[22813:835755] before dispatch_barrier_async //②
 2017-06-29 12:29:32.049 Test - 多线程[22813:835815] ----1-----<NSThread: 0x600000268e00>{number = 5, name = (null)} //③
 2017-06-29 12:29:32.049 Test - 多线程[22813:837436] ----2-----<NSThread: 0x600000267540>{number = 6, name = (null)} //④
 2017-06-29 12:29:32.049 Test - 多线程[22813:835755] after dispatch_barrier_async //⑤
 2017-06-29 12:29:32.049 Test - 多线程[22813:837436] ----barrier-----<NSThread: 0x600000267540>{number = 6, name = (null)} //⑥
 2017-06-29 12:29:32.049 Test - 多线程[22813:835755] barrierAsync end //⑦
 2017-06-29 12:29:32.050 Test - 多线程[22813:837436] ----3-----<NSThread: 0x600000267540>{number = 6, name = (null)} //⑧
 2017-06-29 12:29:32.050 Test - 多线程[22813:835815] ----4-----<NSThread: 0x600000268e00>{number = 5, name = (null)} //⑨
总结:

3.3 迭代dispatch_apply

dispatch_apply : 提交block任务块到调度队列进行多次调度.

三个参数解析:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, DISPATCH_NOESCAPE void (^block)(size_t));

NOTE:

测试代码:

NSLog(@"apply begin");
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
        NSLog(@"index = %zd , thread = %@",index,[NSThread currentThread]);
    });
    NSLog(@"apply end");

测试打印结果:

2017-06-29 14:46:08.973 Test -  多线程[24285:925046] apply begin
2017-06-29 14:46:08.973 Test -  多线程[24285:925046] index = 0 , thread = <NSThread: 0x608000079c00>{number = 1, name = main}
2017-06-29 14:46:08.973 Test -  多线程[24285:925297] index = 1 , thread = <NSThread: 0x608000268600>{number = 7, name = (null)} //①
2017-06-29 14:46:08.973 Test -  多线程[24285:925094] index = 3 , thread = <NSThread: 0x60000026cb40>{number = 5, name = (null)} //②
2017-06-29 14:46:08.973 Test -  多线程[24285:925296] index = 2 , thread = <NSThread: 0x60800026ac80>{number = 6, name = (null)}
2017-06-29 14:46:08.974 Test -  多线程[24285:925046] apply end //③

3.4 一次执行dispatch_once

dispatch_once的作用:保证其block代码块中的代码只执行一次,是线程安全的,常用于实现单例等
数据类型
typedef long dispatch_once_t;

方法,我们在使用的时候,是一个dispatch_once的宏,对应的是一个_dispatch_once的函数._dispatch_once函数两个参数,第一个predicate是标志位,第二个是代码块。

线程安全简单理解:
void
_dispatch_once(dispatch_once_t *predicate,
        DISPATCH_NOESCAPE dispatch_block_t block)
{
    if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
        dispatch_once(predicate, block);
    } else {
        dispatch_compiler_barrier();
    }
    DISPATCH_COMPILER_CAN_ASSUME(*predicate == ~0l);
}

测试代码

dispatch_apply(4, dispatch_get_global_queue(0, 0), ^(size_t index) {
        NSLog(@"------index = %zd",index);
        static dispatch_once_t onceToken; //①
        dispatch_once(&onceToken, ^{//②
            NSLog(@"------run");
        });
     });

测试打印结果

2017-06-29 15:11:57.542 Test -  多线程[24619:946139] ------index = 1
2017-06-29 15:11:57.542 Test -  多线程[24619:946049] ------index = 0
2017-06-29 15:11:57.542 Test -  多线程[24619:946136] ------index = 2
2017-06-29 15:11:57.542 Test -  多线程[24619:946139] ------run

3.5 延迟 dispatch_after

dispatch_after(dispatch_time_t when,
    dispatch_queue_t queue,
    dispatch_block_t block);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"run-----"); // 延迟2秒后提交任务
    });

3.6 线程状态操作: 挂起和恢复队列

注意点:

测试代码:

-   (void)testsuplend
{
    //test1
    //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // dispatch_suspend对全局并发队列无效
    //test2
    //    dispatch_queue_t queue = dispatch_queue_create(NULL, 0); // dispatch_suspend 对串行队列有效
    //test3
    dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); // dispatch_suspend 对自己创建的并发队列有效
    dispatch_async(queue, ^{
        for (int i = 0 ; i < 10; i ++) {
            NSLog(@"---suplend1 --  %zd thread = %@",i,[NSThread currentThread]);
            sleep(1);
        }
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"dispatch_suspend queue one , suplend1打印任务执行完毕后会挂起队列,直到dispatch_resume调用后恢复队列");
        dispatch_suspend(queue);
    });
    
    // 4s后继续添加新的任务,如果在添加之前点击挂起,此任务不会执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_async(queue, ^{
            for (int i = 0 ; i < 10; i ++) {
                sleep(2);
                NSLog(@"---suplend2 --  %zd thread = %@",i,[NSThread currentThread]);
            }
        });
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"dispatch_resume queue one ,---suplend2 --打印任务会恢复执行");
        dispatch_resume(queue);
    });
}

测试打印结果:

2017-06-29 23:31:56.678 Test -  多线程[57328:8371175] ---suplend1 --   0 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:31:57.680 Test - 多线程[57328:8371175] ---suplend1 --   1 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:31:58.682 Test - 多线程[57328:8371175] ---suplend1 --   2 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:31:58.777 Test - 多线程[57328:8371126] dispatch_suspend queue one , suplend1打印任务执行完毕后会挂起队列,直到dispatch_resume调用后恢复队列 //①
     2017-06-29 23:31:59.687 Test - 多线程[57328:8371175] ---suplend1 --   3 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}//②
     2017-06-29 23:32:00.689 Test - 多线程[57328:8371175] ---suplend1 --   4 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:32:01.690 Test - 多线程[57328:8371175] ---suplend1 --   5 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:32:02.677 Test - 多线程[57328:8371126] dispatch_resume queue one ,---suplend2 --打印任务会恢复执行//③
     2017-06-29 23:32:02.692 Test - 多线程[57328:8371175] ---suplend1 --   6 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:32:03.695 Test - 多线程[57328:8371175] ---suplend1 --   7 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}//④
     2017-06-29 23:32:04.682 Test - 多线程[57328:8371177] ---suplend2 --   0 thread = <NSThread: 0x60000027b7c0>{number = 4, name = (null)}//⑤
     2017-06-29 23:32:04.699 Test - 多线程[57328:8371175] ---suplend1 --   8 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
     2017-06-29 23:32:05.702 Test - 多线程[57328:8371175] ---suplend1 --   9 thread = <NSThread: 0x60000027b740>{number = 3, name = (null)}
上一篇 下一篇

猜你喜欢

热点阅读