iOS中的多线程(关于GCD的其他方法)

1,246 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

GCD 栅栏方法

  • 有时需要异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作。这样就需要一个相当于栅栏一样的一个方法将两组异步执行的操作组给分割起来,当然这里的操作组里可以包含一个或多个任务。这就需要用到 dispatch_barrier_async 方法在两个操作组间形成栅栏。

  • dispatch_barrier_async 为分界, 前面的任务执行完才能执行后面的任务

  • dispatch_barrier_async 只在自己创建的 concurrent queue 有效,在 serial queueglobal concurrent queues 中的作用和 dispatch_sync 完全相同

示例:

dispatch_queue_t queue = dispatch_queue_create("com.gcd..queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    for (NSInteger i = 0; i<3; i++) {
        NSLog(@"1----%@",[NSThread currentThread]);
    }
});

dispatch_async(queue, ^{
    for (NSInteger i = 0; i<3; i++) {
        NSLog(@"2----%@",[NSThread currentThread]);
    }
});


dispatch_barrier_async(queue, ^{
    NSLog(@"--barrier--%@",[NSThread currentThread]);
});



dispatch_async(queue, ^{
    for (NSInteger i = 0; i<3; i++) {
        NSLog(@"3----%@",[NSThread currentThread]);
    }
});

dispatch_async(queue, ^{
    for (NSInteger i = 0; i<3; i++) {
        NSLog(@"4----%@",[NSThread currentThread]);
    }
});

log:

Snip20211107_67.png


延时函数

  • dispatch_after 方法并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到主队列中。严格来说,这个时间并不是绝对准确的,但想要大致延迟执行任务,dispatch_after 方法是很有效的。

示例:

NSLog(@"当前线程--0--%@",[NSThread currentThread]);

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"当前线程--1--%@",[NSThread currentThread]);
});

log: Snip20211107_69.png


一次性代码(只执行一次)

在创建单例、或者有整个程序运行过程中只执行一次的代码时,就用到了 GCD 的 dispatch_once 方法。使用 dispatch_once 方法能保证某段代码在程序运行过程中只被执行 1 次,并且即使在多线程的环境下,dispatch_once 也可以保证线程安全

示例:

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"--程序在整个加载过程只会加载一次");
});

快速迭代(主要用于并发队列)

  • 通常用 for 循环遍历,但是GCD提供了快速迭代的方法 dispatch_applydispatch_apply 按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。
  • 在串行队列中使用 dispatch_apply,那么就和 for 循环一样,按顺序同步执行
  • 在并发队列进行异步执行。比如说遍历 0~10 这 10 个数字,for 循环的做法是每次取出一个元素,逐个遍历。dispatch_apply 可以在多个线程中同时(异步)遍历多个数字
  • 无论是在串行队列,还是并发队列中,dispatch_apply 都会等待全部任务执行完毕。

示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"%@--%zu",[NSThread currentThread],index);
});

NSLog(@"遍历完毕");

log:

Snip20211107_70.png