Object-C高级编程读书笔记(6)—— GCD的一些函数

创建Dispatch Queue

Apple的Dispatch Queue有Serial 和 Concurrent之分,但都可以通过

dispatch_queue_create API创建

创建Serial queue:

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL)


值得注意的时,虽然在一个Serial queue中,task的执行是线性的,但是对于多个不同的Serial queue,系统会为每个queue创建一个新的线程,即如果有1000个Serial queue,系统会创建1000个线程,Serial queue之间可以看做是并行的。

 

创建Concurrent queue:

dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);


创建Concurrent queue与创建Serial queue所用函数几乎一样,但在第二个参数中,需要指明创建dispatch queue的类型DISPATCH_QUEUE_CONCURRENT。

 

被废弃的dispatch_retain与dispatch_release

在作者写作OC高级编程一书时,ARC还没有实现对于Dispatch Queue的自动引用计数管理,但在IOS 8.1开始,Dispatch Queue已经和Block一样,均作为了一种Object-C对象来处理,实现了ARC。因此在ARC启用的情况下,

dispatch_retain与dispatch_release是被禁止使用的。

 

变更dispatch queue的优先级 并变更目标队列

当我们想动态的变更执行任务的优先级以及任务队列时,可以使用函数

dispatch_set_target_queue 

该函数有两个功能

1.通过更改目标队列,任务优先级得以对应改变。

2.任务最终在所更改的队列上得以执行。

例:

 

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);

 

 

 

推迟任务的提交时间

有时我们并不想任务立刻提交到dispatch_queue中执行,而是需要推迟一定时间,则可以使用

 

 

 void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); 


对于该函数,有两点需要注意:

 

1. 所谓推迟时间,是大于等于该时间的,系统会待合适的时机将block提交到queue中,并非严格按照when所指定的时间。

2. 推迟的是提交到queue的时间,而并不是执行的时间。block的执行要在提交到queue之后。

 

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3nll * NSEC_PER_SEC);

dispatch_after(time, dispatch_get_main_queue(), ^{
   NSLog(@"waited at least three seconds");
});

 

 

 

dispatch Group

有时候我们提交了多个任务到不同的dispatch_queue中,他们可能并发也可能串行地执行,但是我们有时候可能需要当所有任务执行完毕后,在添加一个final函数,作为结束处理,这时候可以使用Dipatch Group,当同一个group中的任务都执行完毕时,会激发dispatch_group_notify

 

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t myQueue = dispatch_queue_create("com.example.MyQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t finishQueue = dispatch_queue_create("com.example.finishQueue", NULL);

    dispatch_group_async(group, myQueue, ^{NSLog(@"Task 1");});
    dispatch_group_async(group, myQueue, ^{NSLog(@"Task 2");});
    dispatch_group_async(group, myQueue, ^{NSLog(@"Task 3");});
    
    dispatch_group_notify(group, finishQueue, ^{
        NSLog(@"All Done!");


这里的

 

 

dispatch_group_notify

是非阻塞的。

 

 

当我们需要将当前线程挂起来等待group中所有的任务已经结束时,需要使用

dispatch_group_wait 

函数

 

 long dispatch_group_wait( dispatch_group_t group, dispatch_time_t timeout); 


该函数会阻塞当前线程直到指定的timeout。若返回值为0,则说明该函数所等待的函数全部执行完毕,若返回值非0,则说明等待函数尚未全部结束,而是因为超时,函数退出。若要永久等待,timeout 指定为 DISPATCH_TIME_FOREVER

 

 

dispatch_barrier_async

我们知道在并发情况下,对一种资源并发读是安全的,但是若参与了写操作,则可能会引起资源的混乱。针对这种情况,我们可以使用读写锁。GCD中也同样提供了类似的机制,

 

void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);


它能够保证block在执行时,在他之前的block已经执行完毕,同时,在他自己执行完毕前,在他之后的block均不会被执行。

 

 

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, blk0_for_reading);
    dispatch_async(queue, blk1_for_reading);
    dispatch_async(queue, blk2_for_reading);
    dispatch_async(queue, blk3_for_reading);
    
    dispatch_barrier_async(queue, blk_for_writing);
    
    dispatch_async(queue, blk4_for_reading);
    dispatch_async(queue, blk5_for_reading);
    dispatch_async(queue, blk6_for_reading);
    dispatch_async(queue, blk7_for_reading);


 

 

 

 

 

dispatch_apply 

dispatch_apply 函数能够代替loop函数来提高效率。(注意这里的资源必须是可重入的)

 

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


例如我们要遍历一个数组的所有元素,不要求从第一个开始遍历,则可使使用dispatch_apply。注意dispatch_apply是阻塞执行的,因此我们可以在dispatch_aync中执行dispatch_apply

 

 

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    dispatch_apply([array count], queue, ^(size_t index)   {
       NSLog(@"%zu: %@", index, array[index]);
   });
});

 

 

 

dispatch_suspend/dispatch_resume

当我们添加大量处理到Dispatch Queue中后,有时候想要暂停处理,可以调用

 

dispatch_suspend(queue);

 

需要继续时,则调用

 

dispatch_resume(queue)


注意,若在调用suspend前,任务已经开始处理,则该任务不会暂停。

 

 

dispatch Semaphore

对于queue任务之间的同步,可以使用Dispatch Semaphore。顾名思义,它是基于信号量的一种同步。简单的说就是

当计数大于0时,可执行,当技术小于等于0时,不可执行。

创建信号量

 

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);


等待并使用信号量

 

 

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);


释放信号量

 

 

dispatch_semaphore_signal(semaphore);


dispatch_once

 

dispatch_once 可以保证block中的代码在本程序中仅被执行一次,而且是线程安全的。

 

void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);


配合dispatch_once函数使用的,有一个dispatch_once_t 类型的断言,它必须是static或globall类型的,否则结果将会是不可预见的。

 

dispatch_block_create/dispatch_block_cancel

 

我们可以联合dispatch_block_create方法来创建GCD block,通过这种方式创建的block,是可以通过dispatch_block_cancel取消的。注意,已经在GCD queue中执行的block,是不会被cancel的。

- (void)gcdBlockCancel{
    
    dispatch_queue_t queue = dispatch_queue_create("com.gcdtest.www", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_block_t block1 = dispatch_block_create(0, ^{
        sleep(5);
        NSLog(@"block1 %@",[NSThread currentThread]);
    });
    
    dispatch_block_t block2 = dispatch_block_create(0, ^{
        NSLog(@"block2 %@",[NSThread currentThread]);
    });
    
    dispatch_block_t block3 = dispatch_block_create(0, ^{
        NSLog(@"block3 %@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, block1);
    dispatch_async(queue, block2);
    dispatch_block_cancel(block3);
}

 

参考资料

https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_get_global_queue

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值