1)Dispatch Queue
什么是dispatch queue,顾名思义,一个执行处理的等待队列,dispatch queue分为两种,一种是serial queue,另一种是concurrent queue。其创建方式分别为:
dispatch_queue_t serialQ = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t concurrentQ = dispatch_queue_create("myConcurentQ", DISPATCH_QUEUE_CONCURRENT);
尽管现在ARC会为程序员提供自动内存管理技术,但是生成的dispatch queue仍然需要手动释放。
2)Main Queue和global Queue
尽管我们可以手动创建queue,但系统同样给我们提供了两种queue,即Main Queue和global queue。其中Main queue属于serial queue,global queue属于concurrent queue,同时系统针对global queue提供了4个优先级,及High Priority,Default Priority,Low Priority以及Background Priority。由于系统线程的非实时性,因此这个优先级也只是参考。获取系统queue的方式如下:
dispatch_queue_t mainQ = dispatch_get_main_queue(); dispatch_queue_t highPriorityQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_queue_t defaultPriorityQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t lowPriorityQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); dispatch_queue_t backgroundPriorityQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_queue_creat创建出来的queue,无论是Serial queue还是Concurrent Queue,其queue的优先级都为DISPATCH_QUEUE_PRIORITY_DEFAULT.如果需要手动更改Queue的优先级,可以使用dispatch_set_target_queue,
其使用方法为:
dispatch_queue_t serialQ = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t backgroundQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_set_target_queue(serialQ, backgroundQ);
即将serailQ的优先级调整至与backgroundQ一致,此处禁止将系统提供的queue作为第一个参数,否则将会出现不可预料的情况。如果将多个serail queue或者concurrent queue利用此方法设定优先级别到一个serial queue上,则系统将会按照其先后顺序依次执行,而不会并发。
3)dispatch group
我们经常会有这样的需求,即将不同的block追加到同一个queue上面,之后等所有的block执行完成之后,执行一个done的block,为此GCD给我们提供了一个非常简便的方法,即dispatch group.其具体实现如下:
dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行执行的线程一 }); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行执行的线程二 }); dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{ // 汇总结果 });
这样在block1和block2执行完成之后,才会执行notify中得block。
4)dispatch_barrier_async
通常在一个concurrent queue中我们希望并发执行某些操作后,之后的操作独自执行,并不与其它任务并发,在这个操作之后执行结束之后的任务仍然可以并发执行。一个形象的例子就是,一个病重的患者,很多人前来探望,这可以看做并发,之后医生来了说我需要观察病情,所有人探望结束后离开,在医生观察病情之后,说可以了,其他人继续探望吧。在计算机的世界中,可以看做前面都是对某个数据的读操作,之后医生观察病情可以看做是对数据的写操作,之后又是很多的读操作。这种情况用前面给出的内容也都可以实现,但GCD给出了另一种方式,即dispatch_barrier_async。它的使用方式如下:
dispatch_queue_t myQ = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(myQ, block1); dispatch_async(myQ, block2); dispatch_barrier_async(myQ, blockBarrier); dispatch_async(myQ, block3); dispatch_async(serialQ, block4);
其具体的表现行为为并发执行完block1和block2后,会执行blockBarrier,之后再并发执行block3和block4.
5)dispatch_semaphore
dispatch_group_async及dispatch_barrier_async可以很好的解决了大部分问题,但是有的时候我们仍需要对queue里面的任务进行更细粒度的控制,此时就需要用到dispatch_semaphore.顾名思义,信号量,我们通过信号量来完成对queue里面任务的控制。其具体方式如下:
dispatch_queue_t myQ = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_async(myQ, ^{ for (int i = 0; i < 100; i++) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //*** dispatch_semaphore_signal(semaphore); } }); dispatch_release(semaphore);
ps:GCD针对线程管理提供了强大的支持,但仍然不要忘记多线程就是多线程,在进行多线程编程的时候一定要严格考虑各种可能情况的出现,此外,GCD还提供了dispatch_once,dispatch_after,dispatch_sync以及dispatch_async.其中dispatch_once多用于单例的实现,dispatch_after当对时间要求不是特别精准的时候可以采用,dispatch_sync时候注意死锁情况的出现,多用于立即使用现有结果,dispatch_async就不赘述了。
不管别人怎么样,只做更好的自己,加油~