iOS 并行编程之 GCD使用

本文深入探讨了iOS中的并行编程技术,重点介绍了GCD(Grand Central Dispatch)的使用,包括如何利用GCD创建定时器、设置信号处理器、处理Mach port事件以及触发自定义事件。通过这些内容,开发者可以更好地理解和应用GCD,提升iOS应用的性能和响应速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        GCD是Grand Central Dispatch的缩写。其包含了语言特性、runtime libraries以及提供系统级、综合提高的系统增强功能在iOS和OSX 系统上多核的硬件来支持并行执行代码。GCD会负责创建线程和调度执行你写的功能代码。系统直接提供线程管理,比应用添加线程更加高效,因此使用GCD能够带来很多好处,例如使用简单、而且更加高效,允许你同步或者一部执行任意的代码block。但是使用它也必须注意一些问题,由于其实现是基于c语言的API,因此没有异常捕获、异常处理机制,所以它不能捕获高层语言产生的异常。使用GCD时必须在将block提交到dispatch queue中之前捕获所有异常,并解决所有异常。
        说到底,GCD就是系统来帮用户来管理线程,而不需要再编写线程代码。程序员只需要专心编写执行某项功能的代码,添加到block或方法(函数)中,然后可以有下面两种方式来处理block或方法(函数)。
        1.直接将block加入到dispatch queues
        2.将Dispatch source封装为一个特定类型的系统事件,当系统事件发生时提交一个特定的block对象或函数到dispatch queue,
        然后,Dispatch queue 按先进先出的顺序, 串行或并发地执行任务。
        这里,Dispatch queue是一个基于C的执行自定义任务机制,而Dispatch source是基于C的系统事件异步处理机制,一般Dispatch source封装一个特定类型的系统事件,该事件作为某个特定的block对象或函数提交到Dispatch queue中的前提条件。Dispatch source可以监控的系统事件类型有:    

   定时器
   信号处理器 

        描述符相关的事件
  进程相关的事件

   Mach port事件
   你触发的自定义事件 

        而对于Dispatch Queues,其可以分为三种:
         串行Queue
          并发队列
        main dispatch queue
       
        如果使用 dispatch queue,与执行相同功能的多线程相比,最直接的优点是简单,不用编写线程创建和管理的代码,让你集中精力编写实际工作的代码。另外系统管理线程更加高效,并且可以动态调控所有线程。        
       串行Queue,也称为private dispatch queue,其每次只执行一个任务,按任务添加顺序执行。当前正在执行的任务在独立的线程中运行(注意:不同任务的线程可能不同),dispatch queue 管理了这些线程。 通常串行 queue 主要用于对特定资源的同步访问。 你可以创建任意数量的串行queues,虽然每个 queue 本身每 次只能执行一个任务,但是各个 queue 之间是并发执行的。
       并行Queue,也称为 global dispatch queue, 它可以并发执行一个或多个任务,但是所要执行的任务仍然是以添加到 queue 的顺序启动。每个任务运行于独立的线程中,dispatch queue 管理所有线程。同时运行的任务数量随时都会变化,而且依赖于系统条件。值得注意的是,前往不要创建并发 dispatch queues,相反只能使用三个已经定义好的全局并发 queues
       main Dispatch Queue,其实是串行的 queue,不过在应用主线程中执行任务,而且全局可用。这个queue 与应用的 run loop 交叉执行。由于它运行在应用的主线程,main queue 通常用于应用的关键同步点。 虽然你不需要创建 main dispatch queue,但你必须确保应用适当地回收。
        从上面的三种Dispatch Queue可以看出,queue中的任务基本上都是按照添加到queue中的顺序来执行的,因此Dispatch queue 比线程具有更强的可预测性,这种可预测性能够有效的减少程序出错的可能性,而且有效的避免死锁出现。例如两个线程访问共享资源,你可能无法控制哪个线程先后访问;但是把两个任务添加到串行 queue,则可以确保两个任务对共享资源的访问顺序。同时基于 queue 的同步也比基于锁的线程同步机制更加高效。 
        使用dispatch queues 还需要注意的关键问题有
        1. Dispatch queues 相对其它 dispatch queues 并发地执行任务,串行化任务只能在同一个 dispatch queue 中实现。
        2. 系统决定了同时能够执行的任务数量,应用在 100 个不同的 queues 中启动 100 个任务,并不表示 100 个任务全部都在并发地执行(除非系统拥有100 或更多个核) 
        3. 系统在选择执行哪个任务时,会考虑 queue 的优先级。
        4. Queue中的任务必须在任何时候都准备好运行,注意这点和Operation对象不同
        5. 串行 dispatch queue 是引用计数的对象。因此使用它需要 retain 这些 queue,另外 dispatch source 也可能添加到一个 queue,从而增加 retain的计数。因此你必须确保所有 dispatch source 都被取消,而且适当地调用release。 (如果使用了ARC,那么这些就无所谓了!)
        说了这么多,还没有个例子,似乎很不爽,下面就来个例子!
         1.定义一个dispatch_get_global_queue:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//定义一个dispatch_get_global_queue的优先级,以及保留给未来使用的flag值,一般传入的是0。

2.定义一个block,执行真正需要实现的某项功能:
void (^ex)() = ^ {
      NSlog(@"it's example!");
};

注意这里的block是 dispatch_block_t, dispatch_block_t的要求是: The prototype of blocks submitted to dispatch queues, which take no arguments and have no return value.,可以看到其为无行参也无返回类型的block。其基本形式为:
typedef void (^dispatch_block_t)(void);

3.将block加入到dispatch queue
dispatch_async(aQueue , ex);//

可以看到,上面就是使用GCD dispatch queue的例子,代码实现非常简单。但是我们不能因为它使用简单就随意使用,是否使用GCD,主要看其block所执行的功能。设计block需要考虑以下问题:
1.尽管 Queue 执行小任务比原始线程更加高效,仍然存在创建 Block 和在 Queue 中执行的开销。如果 Block 做的事情太少,可能直接执行比 dispatch 到 queue 更加有效。使用性能工具来确认 Block 的工作是否太少 ——设计block和是否使用dispatch queue主要关注的点。
2.对于使用dispatch queue 的异步Block,可以在 Block 中安全地捕获和使用父函数或方法中的 scalar 变量。但是 Block不应该去捕获大型结构体或其它基于指针的变量,这些变量由 Block 的调用上下文分配和删除。在你的 Block 被执行时,这些指针引用的内存可能已经不存在。当然,你自己显 式地分配内存(或对象),然后让 Block 拥有这些内存的所有权,是安全 可行的。 
3.Dispatch queue对添加的Block会进行复制,在完成执行后自动释放。也就是你不需要在添加 Block 到 Queue 时显式地复制。
4. 绝对不要针对底层线程缓存数据,然后期望在不同 Block 中能够访问这些 数据。如果相同 queue 中的任务需要共享数据,应该使用 dispatch queue 的 context 指针来存储这些数据。 
5.如果Block创建了大量Objective-C对象,考虑创建自己的autoreleasepool, 来处理这些对象的内存管理。虽然 GCD dispatch queue 也有自己的 autorelease pool,但不保证在什么时候会回收这些 pool。

        GCD属于iOS并行编程的主要部分,具体的内容可以参考:Concurrency Programming Guide
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值