GCD使用笔记

本文详细介绍了GCD(Grand Central Dispatch)的使用,包括dispatch_queue_t的创建与类型、dispatch_set_target_queue设置目标队列、dispatch_after延时操作、dispatch_semaphore_t信号量作为线程同步工具、dispatch_once确保代码只执行一次、dispatch_suspend和dispatch_resume暂停与恢复队列、dispatch_group任务组管理以及dispatch_apply并发执行任务。同时,重点讲解了dispatch_barrier_async如何实现屏障操作,确保其内部任务在其他任务执行完毕后才进行。
摘要由CSDN通过智能技术生成

dispatch_queue_t

  • 获得主队列

dispatch_queue_t main_queue = dispatch_get_main_queue();

  • 创建串行队列

    dispatch_queue_t serial_queue = dispatch_queue_create(“name”, DISPATCH_QUEUE_SERIAL);

  • 创建并行队列

    dispatch_queue_t concurrent_queue = dispatch_queue_create(“name”, DISPATCH_QUEUE_CONCURRENT);

  • 获取全局并发队列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_set_target_queue

dispatch_set_target_queue 1、指定 Dispatch Queue 执行优先级;2、设置执行阶层

dispatch_after

dispatch_after指定时间后将任务追加到主队列中。所谓延迟提交,不是延迟执行。因此严格来说这个时间并不是绝对准确的。

dispatch_semaphore_t

dispatch_semaphore_t可以更细的控制资源。在多线程中很经常当做‘锁’使用,例:

 // 创建一个 Semaphore 并初始化信号的总量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
 
// 使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

//do.....
 
// 发送一个信号,让信号总量加 1
dispatch_semaphore_signal(semaphore);

dispatch_once

只会执行一次,经常用于单利创建

+ (instancetype)sharedManager {
    static XXManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];

    });
    return manager;
}

dispatch_suspend/dispatch_resume

dispatch_suspend 暂停队列(注意,对于已经开始的任务不会挂起),dispatch_resume恢复队列;

dispatch_group

作用

Dispatch Group 用于整个组的任务都完成时通知你。
这些任务可以是同步的,也可以是异步的,即便在不同的队列也行。
而且在整个组的任务都完成时,Dispatch Group 可以用同步的或者异步的方式通知你.

使用方式

调用队列组的 dispatch_group_async 先把任务放到队列中,然后将队列放入队列组中。
或者使用队列组的 dispatch_group_enter、dispatch_group_leave 组合来实现 dispatch_group_async。
调用队列组的 dispatch_group_notify 回到指定线程执行任务。或者使用 dispatch_group_wait 回到当前线程继续向下执行(会阻塞当前线程)

dispatch_group_notify

监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务

-(void)test_group_01{
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-01:%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-02:%@",[NSThread currentThread]);
    });

    NSLog(@"flag.....");
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"任务完成");
    });
    NSLog(@"end.....");

}
    //打印
    flag.....
    task-02:<NSThread: 0x6000010e4400>{number = 5, name = (null)}
    end.....
    task-01:<NSThread: 0x6000010e4240>{number = 6, name = (null)}
    任务完成

dispatch_group_wait

会阻塞当前线程,直到组里面所有的任务都完成或者等到某个超时发生

-(void)test_group_02{
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-01:%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-02:%@",[NSThread currentThread]);
    });
    
    NSLog(@"flag.....");

    //dispatch_group_wait,会阻塞当前线程,直到组里面所有的任务都完成或者等到某个超时发生.
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"任务完成");
    
   //打印
   flag.....
   task-01:<NSThread: 0x600000260980>{number = 4, name = (null)}
   task-02:<NSThread: 0x600000260780>{number = 6, name = (null)}
   任务完成
}

dispatch_group_enter、dispatch_group_leave

必须保证 dispatch_group_enter 和 dispatch_group_leave 成对出现,否则你可能会遇到诡异的崩溃问题


-(void)test_group_03{
    
    dispatch_group_t group = dispatch_group_create();//create
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_enter(group);//enter
    dispatch_group_async(group, queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-01:%@",[NSThread currentThread]);
    });
    dispatch_group_leave(group);//leave
    
    dispatch_group_enter(group);//enter
    dispatch_group_async(group, queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-02:%@",[NSThread currentThread]);
    });
    dispatch_group_leave(group);//leave
    
    dispatch_group_enter(group);//enter
    dispatch_group_async(group, queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-03:%@",[NSThread currentThread]);
    });
    dispatch_group_leave(group);//leave

    NSLog(@"flag.....");
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"任务完成");
    });
}

   // 打印
    flag.....
    task-01:<NSThread: 0x60000067b080>{number = 5, name = (null)}
    task-03:<NSThread: 0x600000635100>{number = 3, name = (null)}
    task-02:<NSThread: 0x600000670480>{number = 4, name = (null)}
    任务完成
    

dispatch_apply

dispatch_apply表现得就像一个 for 循环,但它能并发地执行不同的迭代。这个函数是同步的,所以和普通的 for 循环一样,它只会在所有工作都完成后才会返回。

当在 Block 内计算任何给定数量的工作的最佳迭代数量时,必须要小心,因为过多的迭代和每个迭代只有少量的工作会导致大量开销以致它能抵消任何因并发带来的收益。而被称为跨越式(striding)的技术可以在此帮到你,即通过在每个迭代里多做几个不同的工作

那何时才适合用 dispatch_apply 呢?

  • 自定义串行队列:串行队列会完全抵消 dispatch_apply 的功能;你还不如直接使用普通的 for 循环。
  • 主队列(串行):与上面一样,在串行队列上不适合使用 dispatch_apply 。还是用普通的 for 循环吧。
  • 并发队列:对于并发循环来说是很好选择,特别是当你需要追踪任务的进度时
- (void)test_apply{
    dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) {
        sleep(arc4random()%10*0.5);
        NSLog(@"task-%ld:%@",i,[NSThread currentThread]);
    });
    NSLog(@"flag....");
}

	// 打印
    task-3:<NSThread: 0x600002d45000>{number = 6, name = (null)}
    task-2:<NSThread: 0x600002d6e540>{number = 3, name = (null)}
    task-4:<NSThread: 0x600002d78180>{number = 5, name = (null)}
    task-1:<NSThread: 0x600002d70480>{number = 4, name = (null)}
    task-0:<NSThread: 0x600002d24f00>{number = 1, name = main}
    flag....

dispatch apply 是同步的,可以在主线程走任务,如果想异步可以在外面包一层


    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) {
            sleep(arc4random()%10*0.5);
            NSLog(@"task-%ld:%@",i,[NSThread currentThread]);
        });
    });
    NSLog(@"flag....");
    
    打印:
    flag....
    task-4:<NSThread: 0x600002bb02c0>{number = 6, name = (null)}
    task-3:<NSThread: 0x600002ba4000>{number = 8, name = (null)}
    task-1:<NSThread: 0x600002bbab00>{number = 7, name = (null)}
    task-2:<NSThread: 0x600002ba5280>{number = 9, name = (null)}
    task-0:<NSThread: 0x600002ba1300>{number = 10, name = (null)}

dispatch_barrier_async

方法会等待前面追加到并发队列中的任务全部执行完毕之后,再将自己指定的任务追加到该异步队列中,任务执行完毕之后,异步队列才恢复为一般动作,接着追加后面任务到该异步队列并开始执行


-(void)test_barrier{
    dispatch_queue_t queue = dispatch_queue_create("queue_name", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-01:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-02:%@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-barrier:%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-03:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        sleep(arc4random()%10*0.5);
        NSLog(@"task-04:%@",[NSThread currentThread]);
    });
    
}

    打印:
    task-01:<NSThread: 0x6000006ee7c0>{number = 5, name = (null)}
    task-02:<NSThread: 0x6000006e9e40>{number = 4, name = (null)}
    task-barrier:<NSThread: 0x6000006e9e40>{number = 4, name = (null)}
    task-04:<NSThread: 0x6000006ee7c0>{number = 5, name = (null)}
    task-03:<NSThread: 0x6000006e9e40>{number = 4, name = (null)}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值