GCD(Grand Central Dispatch)

来源:互联网 发布:windows字体库 编辑:程序博客网 时间:2024/04/29 13:44

什么是GCD?

GCD是异步执行任务的技术之一。它通过向系统管理的调度队列(dispatch queues)中提交工作,在多核硬件上同时执行代码。


GCD特点

  • 提高执行效率:
由于GCD提供的是系统级的线程管理,因此其执行效率要高于其它多线程处理方法。
  • 使用起来非常简单:
//在后台线程中执行dispatch_async(queue, ^{    //想执行的任务});//在主线程中执行dispatch_async(dispatch_get_main_queue(), ^{    //想执行的任务});

仅一行代码就能在指定线程中执行相应操作。


Dispatch Queue

Dispatch Queue:调度队列,用来管理你提交给它的任务。所有的Dispatch Queue都是先进先出(FIFO)的数据结构。

这里写图片描述

Dispatch Queue种类 说明 serial Dispatch Queue 串行队列,按照它们添加到队列中的顺序逐一执行任务,经常用来同步访问指定资源 Concurrent Dispatch Queue 并发队列,同时执行一个或多个任务,仍以添加到队列中的顺序来开始一个任务的 Main Dispatch Queue 主队列,是一个全局可用的串行队列,在应用程序的主线程中执行任务

serial Dispatch Queue:

这里写图片描述

Concurrent Dispatch Queue:
这里写图片描述


创建和管理调度队列

创建串行队列和并行队列都是使用dispatch_queue_create()函数,它有两个参数,第一个指明队列的名称,第二个参数指明队列是串行的还是并发的。其返回值是dispatch_queue_t类型。

创建串行的调度队列

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.MyQueue", NULL);diapatch_async(mySerialDispatchQueue, ^{})
  • 当生成多个Serial Dispatch Queue时,各个Serial Dispatch Queue将并行执行。

这里写图片描述

  • 在多个线程更新相同资源导致数据竞争时使用serial Dispatch Queue。

这里写图片描述

注意:

虽然使用dispatch_queue_create()可以生成任意多个Serial Dispatch Queue,但如果过多的使用多线程,就会消耗大量的内存,引起大量的上下文切换,大幅度降低系统的响应性能。

创建并发的调度队列

在执行不发生数据竞争等问题的处理时,使用Concurrent Dispatch Queue。

dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.example.myQueue", DISPATCH_QUEUE_CONCURRENT);diapatch_async(myConcurrentDispatchQueue, ^{})

对于Concurrent Dispatch Queue来说,不管生成多少个,由于XNU内核只使用有效管理的线程,因此不会出现Serial Dispatch Queue的问题。

全局并发调度队列

系统为每个应用程序提供了一个全局的并发队列,你不需要显示的来创建它们。你只需要使用diapatch_get_global_queue()函数来使用它们:

dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

它有4个执行优先级,分别是:

  • DISPATCH_QUEUE_PRIORITY_DEFAULT:默认优先级
  • DISPATCH_QUEUE_PRIORITY_HIGH:高优先级
  • DISPATCH_QUEUE_PRIORITY_LOW:低优先级
  • DISPATCH_QUEUE_PRIORITY_BACKGROUND:后台优先级

注意:
dispatch_get_global_queue()的第二个函数是预留给未来扩展使用的,现在,你总是传0即可。

主调度队列

主调度队列的获取方法:

dispatch_queue_t mainQueue = dispatch_get_main_queue();

主调度队列是在主线程中执行的,因为主线程只有一个,所以主调度队列自然就是Serial Dispatch Queue。


调度队列的内存管理

调度队列和其它的调度对象不能使用ARC进行自动内存管理,必须由程序员手动进行内存管理。这是因为调度队列和调度对象不具有作为Objective-C对象来处理的技术。

  • 通过dispatch_queue_create()函数生成的dispatch_queue_t在使用结束后,要通过dispatch_release()函数释放。
dispatch_release(mySerialDispatchQueue);
  • 相应的也可以通过dispatch_retain函数,是dispatch对象的引用计数加1。
dispatch_retain(myConcurrentDispatchQueue);
  • tips:
dispatch_queue_t queue = dispatch_queue_create("com.example.myQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{    NSLog(@"block on queue!");})dispatch_release(queue);

使用dispatch_async()函数将Block追加Concurrent Dispatch Queue中,并立即通过dispatch_release()函数进行释放是否可以呢?

该源代码完全没有问题。将Block追加到Concurrent Dispatch Queue中时,Block就会通过dispatch_retain函数持有Dispatch Queue。无论是serial Dispatch Queue还是Concurrent Dispatch Queue都是一样的。一旦Block执行结束,就会通过dispatch_release函数释放该Block持有的Dispatch Queue。

注意:
你不需要对全局的调度队列进行retain或release操作,包括并发的调度队列或主调度队列。任何retain或release队列的操作都会被忽视。

1 0