码迷,mamicode.com
首页 > 移动开发 > 详细

iOS中的GCD多线程

时间:2015-08-08 10:32:05      阅读:272      评论:0      收藏:0      [点我收藏+]

标签:gcd   并发   多线程   ios   

GCD为Grand Central Dispatch的缩写

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并行任务。

GCD提供给我们一个简易使用的并发模型,通过推迟昂贵的计算任务来提高应用的响应性能

GCD 提供有 dispatch queues 来处理代码块,这些队列管理你提供给 GCD 的任务并用 FIFO 顺序执行这些任务。这就保证了第一个被添加到队列里的任务会是队列中第一个开始的任务,而第二个被添加的任务将第二个开始,如此直到队列的终点。 GCD 提供给你至少五个特定的队列,可根据队列类型选择使用。

主线程是唯一可以更改UI的线程,当你需要对UI进行操作的时候,为了减少卡顿最好把它们放在main queue里面

全局调度队列有四个,分别有着不同的优先级: background low default high, 而且你也可以创建自己的队列

        func dispatch_async(_ queue: dispatch_queue_t,
            _ block: dispatch_block_t)

该函数是GCD的使用中最常用的函数,传入两个参数,第二个参数为一个闭包,里面包含了需要被执行的操作,第一个参数是个队列,表明该闭包应该在哪个队列上执行,该函数立即返回,不会等待整个闭包操作的执行完成

        func dispatch_after(_ when: dispatch_time_t,
           
_ queue: dispatch_queue_t,
            _ block: dispatch_block_t)

该函数相当于一个延迟版的dispatch_async,第一个参数表明多少纳秒后开始执行该函数

通过if条件语句来确保单例只被实例化一次并不是靠谱的选择,这时采用下面的函数能够保证单例真的是单例

        func dispatch_once(_ predicate: UnsafeMutablePointer<dispatch_once_t>,
            _ block: dispatch_block_t)

是否会被初始化多次并不是单例面临的唯一问题,当一个实例在被读取的过程中同时被写是线程不安全的,在自定义并发队列中,你可以选择采用以下函数来解决

        func dispatch_barrier_async(_ queue: dispatch_queue_t,
            _ block: dispatch_block_t)

Dispatch barriers 是一组函数,在并发队列上工作时扮演一个串行式的瓶颈。使用 GCD 的障碍(barrier)API 确保提交的 Block 在那个特定时间上是指定队列上唯一被执行的条目。这就意味着所有的先于调度障碍提交到队列的条目必能在这个 Block 执行前完成。
 
当这个 Block 的时机到达,调度障碍执行这个 Block 并确保在那个时间里队列不会执行任何其它 Block 。一旦完成,队列就返回到它默认的实现状态。 GCD 提供了同步和异步两种障碍函数。

当你需要保证写在异步闭包里的一个操作必须要等前一个操作完成时才能开始的时候,你会需要使用到同步函数

        func dispatch_barrier_sync(_ queue: dispatch_queue_t,
            _ block: dispatch_block_t)

dispatch_sync() 同步地提交工作并在返回前等待它完成,将该函数放在主队列和自定义串行队列很有可能会导致死锁,最好的选择是将其放在并发队列中

解决对多个异步任务的完成进行监控的问题,是设计 dispatch_group 的目的

Dispatch Group 会在整个组的任务都完成时通知你。这些任务可以是同步的,也可以是异步的,即便在不同的队列也行。而且在整个组的任务都完成时,Dispatch Group 可以用同步的或者异步的方式通知你。因为要监控的任务在不同队列,那就用一个 dispatch_group_t 的实例来记下这些不同的任务

有些方法的末尾写着一些CompletionBlock,但当方法内部存在异步操作的时候,CompletionBlock就可能在所有操作未完全完成前被调用

为了解决这个问题,我们可以用到dispatch_group_wait 

因为使用的dispatch_group_wait是同步的 ,它会阻塞当前线程,所以你要用 dispatch_async 将整个方法放入后台队列以避免阻塞主线程
在内部用dispatch_group_create()来创建一个新的dispatch_group_t实例
dispatch_group_enter(dispatch_group_t实例)来进入一个group
dispatch_group_leave(同一个dispatch_group_t实例)来离开一个group
dispatch_group_wait(同一个dispatch_group_t实例,等待时间)来同步的等待该group内的所有操作执行完成
当工作执行完成后可采用dispatch_asyn函数异步切回主线程执行后续操作

若采用dispatch_group_notify来替换dispatch_group_wait的话,就不需要在开头调用dispatch_async将方法放入其它队列,因为该方法是异步的,最后也不需要单独的dispatch_async,原闭包内的操作可以直接写在dispatch_group_notify的闭包中,但当然也要将操作放在主队列中

        func dispatch_apply(_ iterations: Int,
           
_ queue: dispatch_queue_t!,
            _ block: (Int) -> Void)

在自定义并发队列里采用上方函数可以并发的执行迭代操作以提高性能,但对于小集合来说,并发执行所带来的性能优化可能并不如多创建并运行一个线程的开销大

版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS中的GCD多线程

标签:gcd   并发   多线程   ios   

原文地址:http://blog.csdn.net/nsnirvana/article/details/47355337

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!