GCD多线程的使用(一)
苹果官方给的解释是:Grand Central Dispatch(GCD)是异步执行任务的技术之一。GCD的线程管理是作为系统的一部分来实现的,因此可以统一管理,也可执行任务,比以前的线程更有效率,这也是苹果推荐使用的技术。
苹果官方对GCD的说明:开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。这句话有三个关键点:
1、想执行的任务。
2、追加。
3、适当的Dispatch Queue。
用代码比较好说明这三点:
dispatch_async(queue, ^{ //想执行的任务 });
想执行的任务使用Block来定义,通过dispatch_async函数来将定义好的任务追加到适当的Dispatch Queue即queue中。其中,Dispatch Queue是一个dispatch_queue_t类型的变量,是通过函数dispatch_queue_create来创建,Dispatch Queue有两种类型:
1、Serial Dispatch Queue:串行,等待现在执行中处理结束。
2、Concurrent Dispatch Queue:并行,不等待现在执行中处理结束。
追加也有两种方式:
1、dispatch_sync:同步
2、dispatch_async:异步
所以,从现在看来,在使用GCD进行多线程编程的时候主要由以下四种:
1、Serial Dispatch Queue+dispatch_sync
2、Serial Dispatch Queue+dispatch_async
3、Concurrent Dispatch Queue+dispatch_sync
4、Concurrent Dispatch Queue+dispatch_async
串行是指从事某项工作时一个步骤一个步骤的去实施,在上一个步骤没有完成的时候是不能开始下一个步骤的,放到GCD里面来说就是想执行的任务需要一个一个来处理,在上一个没有处理完成时,下一个任务需要等待;并行和串行相对,它在一个任务未处理完成时就可以执行另外一个任务,无需等待前面的任务完成;dispatch_sync是将任务添加到指定线程中,当前线程会被阻塞,等待任务在指定线程完成后才会继续往下执行;而dispatch_async在将任务添加到指定线程中得时候不会阻塞当前线程,会继续执行下去。下面用代码来解释这四种方式。
1、Serial Dispatch Queue+dispatch_sync
/** * 串行+同步(serial+sync) */ - (void)serialSyncQueue { dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ NSLog(@"%@:queue serialSyncQueue 0", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@:queue serialSyncQueue 1", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@:queue serialSyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 serialSyncQueue 0", [NSThread currentThread]); }); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 serialSyncQueue 1", [NSThread currentThread]); }); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 serialSyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue1); }
代码的意思是创建了两个串行的Dispatch Queue:queue和queue1,然后分别在这两个Dispatch Queue中用dispatch_sync添加了三个Block,输出结果如下:
2015-06-14 09:10:40.296 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue serialSyncQueue 0 2015-06-14 09:10:40.298 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue serialSyncQueue 1 2015-06-14 09:10:40.298 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue serialSyncQueue 2 2015-06-14 09:10:40.299 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue1 serialSyncQueue 0 2015-06-14 09:10:40.299 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue1 serialSyncQueue 1 2015-06-14 09:10:40.299 GCD_Study[16616:607] <NSThread: 0x8c12ed0>{name = (null), num = 1}:queue1 serialSyncQueue 2
输出中,num = 1表示当前线程是主线程。通过观察执行顺序可以得知,Serial Dispatch Queue+dispatch_sync:任务是在主线程中按照添加的先后顺序进行执行。
2、Serial Dispatch Queue+dispatch_async
/** * 串行+异步(serial+async) */ - (void)serialAsyncQueue { dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ NSLog(@"%@:queue serialAsyncQueue 0", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@:queue serialAsyncQueue 1", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@:queue serialAsyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 serialAsyncQueue 0", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 serialAsyncQueue 1", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 serialAsyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue1); }
同样是创建了两个串行的Dispatch Queue,然后用dispatch_async函数分别往两个Dispatch Queue中添加任务。输出结果如下:
2015-06-14 09:16:17.131 GCD_Study[16639:1303] <NSThread: 0x8f04d10>{name = (null), num = 2}:queue serialAsyncQueue 0 2015-06-14 09:16:17.131 GCD_Study[16639:3103] <NSThread: 0x8e1de20>{name = (null), num = 3}:queue1 serialAsyncQueue 0 2015-06-14 09:16:17.134 GCD_Study[16639:1303] <NSThread: 0x8f04d10>{name = (null), num = 2}:queue serialAsyncQueue 1 2015-06-14 09:16:17.135 GCD_Study[16639:1303] <NSThread: 0x8f04d10>{name = (null), num = 2}:queue serialAsyncQueue 2 2015-06-14 09:16:17.135 GCD_Study[16639:3103] <NSThread: 0x8e1de20>{name = (null), num = 3}:queue1 serialAsyncQueue 1 2015-06-14 09:16:17.136 GCD_Study[16639:3103] <NSThread: 0x8e1de20>{name = (null), num = 3}:queue1 serialAsyncQueue 2
num = 2,和num = 3 说明新开了两个线程,执行顺序也不是遵循添加的先后顺序了。
3、Concurrent Dispatch Queue+dispatch_sync
/** * 并行+同步(concurrent+sync) */ - (void)concurrentSyncQueue { dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(queue, ^{ NSLog(@"%@:queue concurrentSyncQueue 0", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@:queue concurrentSyncQueue 1", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@:queue concurrentSyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 concurrentSyncQueue 0", [NSThread currentThread]); }); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 concurrentSyncQueue 1", [NSThread currentThread]); }); dispatch_sync(queue1, ^{ NSLog(@"%@:queue1 concurrentSyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue1); }
创建了两个并行的Dispatch Queue,然后用dispatch_sync分别添加Block。因为dispatch_sync是同步添加的,添加的任务处理完成后才可继续往下执行,所以输出结果应该和第一种方式一样:
2015-06-14 09:21:31.712 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue concurrentSyncQueue 0 2015-06-14 09:21:31.713 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue concurrentSyncQueue 1 2015-06-14 09:21:31.714 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue concurrentSyncQueue 2 2015-06-14 09:21:31.714 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue1 concurrentSyncQueue 0 2015-06-14 09:21:31.715 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue1 concurrentSyncQueue 1 2015-06-14 09:21:31.715 GCD_Study[16677:607] <NSThread: 0x8d00080>{name = (null), num = 1}:queue1 concurrentSyncQueue 2
尽管添加进得queue是并行的,但是受到添加方式的约束,并不能并行执行。
4、Concurrent Dispatch Queue+dispatch_async
/** * 并行+异步(concurrent+async) */ - (void)concurrentAsyncQueue { dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@"%@:queue concurrentAsyncQueue 0", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@:queue concurrentAsyncQueue 1", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@:queue concurrentAsyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 concurrentAsyncQueue 0", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 concurrentAsyncQueue 1", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1 concurrentAsyncQueue 2", [NSThread currentThread]); }); dispatch_release(queue1); }
创建了两个并发的Dispatch Queue,然后用异步添加的方式分别给两个queue添加了三个任务。
输出结果如下:
2015-06-14 09:28:08.306 GCD_Study[16688:3603] <NSThread: 0x8d214c0>{name = (null), num = 6}:queue1 concurrentAsyncQueue 1 2015-06-14 09:28:08.305 GCD_Study[16688:1303] <NSThread: 0x8e09850>{name = (null), num = 2}:queue concurrentAsyncQueue 0 2015-06-14 09:28:08.305 GCD_Study[16688:3303] <NSThread: 0x8f05c90>{name = (null), num = 4}:queue concurrentAsyncQueue 2 2015-06-14 09:28:08.305 GCD_Study[16688:3103] <NSThread: 0x8d21360>{name = (null), num = 3}:queue concurrentAsyncQueue 1 2015-06-14 09:28:08.306 GCD_Study[16688:3703] <NSThread: 0x8c4b440>{name = (null), num = 7}:queue1 concurrentAsyncQueue 2 2015-06-14 09:28:08.305 GCD_Study[16688:3403] <NSThread: 0x8c4b490>{name = (null), num = 5}:queue1 concurrentAsyncQueue 0
看起来和第二种方式有点类似,第二种方式只创建了两个线程,两个queue因为是串行的,它们在各自的线程中还是按照添加的先后顺序来执行的,而现在这种方式因为queue是并发的,又用的异步方式添加的,所以每个queue中得任务都需要新建一个线程来执行,顺序也没有遵循添加的先后顺序。