ios-多线程-GCD

ios-多线程-GCD

首先,得来点正式的开场:咳咳咳!!!
Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写。从基本功能上讲,GCD有点像 NSOperationQueue,他们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。GCD比之 NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分。
下面开始本菜鸟的对GCD的某些菜鸟级别的理解。如果你不幸看到我这篇文章,如果你是大神,请点(左/右)上角的叉叉。如果你继续看下去,恭喜你,你和我的等级差不多,就不要瞎逼逼了。
 

同步和异步

其次,你得明白啥叫同步,啥叫异步!或许你已经知道,但好像脑子里一片空白,讲不出个所以然,那和我一样。以下个人理解,网上的看的有点乱。
 
同步:请求发过去了,必须等待有响应返回才继续执行下一步;若没有响应返回,会一直卡在发请求的那里,不会继续执行下去。既然各请求的执行有这种关联关系,那么同步就是一个单线程(理解这一点很重要),所有采用同步方法来执行的请求,都是在主线程中执行。因为同步,所以必须等待上一个请求执行完毕才能执行下一个请求,你不把它们放在一个线程中,怎么有这种依赖关系呢?!
异步:请求发过去了,无需等待响应的返回,继续执行下一步。okay,就是与同步相反,下一个请求的执行不必依赖于上一个请求,各请求的执行都是相互独立的,既然独立,那么就肯定要为这些队列开启新线程了。所以,异步是肯定要开启新线程的。你不把它们各放在一个线程中来消除彼此之间的关联,它们怎么能各执行各的呢?!
 

GCD

介绍上述,再来看GCD
GCD有三种队列:全局队列、串行队列和主队列

1.全局队列:

所有添加到全局队列中任务都是并发执行

定义全局队列:dispatch_queue_t queue = dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

可以往这个全局队列中塞各种任务,为执行这些队列,可能会开启多个线程,为什么可能呢?如果方法是同步,则不会开启新线程;如果方法是异步,会开启新线程,线程个数:随机(个人理解)

方法是谁?就是异步方法:dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>);同步方法:dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>);不废话,直接上代码!

- (IBAction)click2 {    
    NSLog(@"click2---%@",[NSThread currentThread]);
    /*
     GCD 3种队列
     全局队列:所有添加到全局队列中任务都是并发执行的(同时执行,可能会开启多个线程) dispatch_get_global_queue
     串行队列:所有添加到串行队列中任务都是按顺序执行的(可能开一条线程)dispatch_queue_create
     主队列:所有添加到主队列中任务都是在主线程中执行的 dispatch_get_main_queue()
     
     同步还是异步,取决于方法名
     dispatch_sync:同步:在当前线程执行任务,不会开启新的线程
     dispatch_async:异步:在其他线程执行任务,会开启新的线程,开启多少条线程:随机
     */
    
    // 全局队列(同时执行,可能会开启多个线程:如果方法是同步,则不会开启新线程;如果方法是异步,会开启新线程,线程个数:随机)
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   // 异步执行队列(在其他线程执行任务,会开启新的线程,开启多少条线程:随机)
    dispatch_async(queue, ^{
        // 耗时操作
        NSLog(@"dispatch_async queue---%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        // 耗时操作
        NSLog(@"dispatch_async queue---%@",[NSThread currentThread]);
    });
    
    // 同步执行队列(在当前线程执行任务,不会开启新的线程,无论队列个数有多少个)
    dispatch_sync(queue, ^{
        // 耗时操作
        NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        // 耗时操作
        NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]);
    });
}

我们来看输出:

2015-04-22 17:47:42.240 多线程[869:29397] 主线程---<NSThread: 0x7fce69e0de80>{number = 1, name = main}
2015-04-22 17:47:43.102 多线程[869:29397] click2---<NSThread: 0x7fce69e0de80>{number = 1, name = main}
2015-04-22 17:47:43.102 多线程[869:29397] dispatch_sync queue---<NSThread: 0x7fce69e0de80>{number = 1, name = main}
2015-04-22 17:47:43.102 多线程[869:29397] dispatch_sync queue---<NSThread: 0x7fce69e0de80>{number = 1, name = main}
2015-04-22 17:47:43.102 多线程[869:29419] dispatch_async queue---<NSThread: 0x7fce69d324f0>{number = 2, name = (null)}
2015-04-22 17:47:43.102 多线程[869:29421] dispatch_async queue---<NSThread: 0x7fce69d314d0>{number = 3, name = (null)}

先看同步执行队列方法:dispatch_sync,我们看到这两个队列都采用同步方法执行,故系统不会为这两个队列开启新的线程,直接在主线程中执行。无论有多少个队列,只要都采用同步方法来执行,就是只在主线程中执行。

在看异步执行队列方法:dispatch_async,我们看到这两个队列都采用异步方法执行,故系统会分别为这两个队列各开启一个新的线程,来执行他们,可以看出这两个队列明显不是在一个线程中执行的。事实上,系统检测到有多个队列且采用异步方法执行时,会“随机”分配可用的线程给这些队列,即开启的新线程数并不完全等于异步方法个数,但绝对会开启新线程

 上代码!

 

- (IBAction)click2 {    
    NSLog(@"click2---%@",[NSThread currentThread]);    
    /*
     GCD 3种队列
     全局队列:所有添加到全局队列中任务都是并发执行的(同时执行,可能会开启多个线程) dispatch_get_global_queue
     串行队列:所有添加到串行队列中任务都是按顺序执行的(可能开一条线程)dispatch_queue_create
     主队列:所有添加到主队列中任务都是在主线程中执行的 dispatch_get_main_queue()
     
     同步还是异步,取决于方法名
     dispatch_sync:同步:在当前线程执行任务,不会开启新的线程
     dispatch_async:异步:在其他线程执行任务,会开启新的线程,开启多少条线程:随机
     */
    
    // 全局队列(同时执行,可能会开启多个线程:如果方法是同步,则不会开启新线程;如果方法是异步,会开启新线程,线程个数:随机)
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
// 异步执行队列(在其他线程执行任务,会开启新的线程,开启多少条线程:随机)
dispatch_async(queue, ^{ // 耗时操作 NSLog(@"dispatch_async queue---%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ // 耗时操作 NSLog(@"dispatch_async queue---%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ // 耗时操作 NSLog(@"dispatch_async queue---%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ // 耗时操作 NSLog(@"dispatch_async queue---%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ // 耗时操作 NSLog(@"dispatch_async queue---%@",[NSThread currentThread]); }); // 同步执行队列(在当前线程执行任务,不会开启新的线程,无论队列个数有多少个) dispatch_sync(queue, ^{ // 耗时操作 NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ // 耗时操作 NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ // 耗时操作 NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ // 耗时操作 NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ // 耗时操作 NSLog(@"dispatch_sync queue---%@",[NSThread currentThread]); }); }

 

上面有5个待执行的采用异步执行方法全局队列,5个待执行的采用同步执行方法的全局队列

输出结果:

2015-04-22 18:08:43.807 多线程[1073:37744] click2---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.808 多线程[1073:37744] dispatch_sync queue---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.808 多线程[1073:37948] dispatch_async queue---<NSThread: 0x7ff27240a780>{number = 4, name = (null)}
2015-04-22 18:08:43.808 多线程[1073:37744] dispatch_sync queue---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.809 多线程[1073:37744] dispatch_sync queue---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.809 多线程[1073:37744] dispatch_sync queue---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.809 多线程[1073:37744] dispatch_sync queue---<NSThread: 0x7ff272610300>{number = 1, name = main}
2015-04-22 18:08:43.809 多线程[1073:37948] dispatch_async queue---<NSThread: 0x7ff27240a780>{number = 4, name = (null)}
2015-04-22 18:08:43.810 多线程[1073:37948] dispatch_async queue---<NSThread: 0x7ff27240a780>{number = 4, name = (null)}
2015-04-22 18:08:43.808 多线程[1073:37949] dispatch_async queue---<NSThread: 0x7ff27251ade0>{number = 6, name = (null)}
2015-04-22 18:08:43.810 多线程[1073:37948] dispatch_async queue---<NSThread: 0x7ff27240a780>{number = 4, name = (null)}

我们看到采用同步执行方法(dispatch_sync)的全局队列都是在{number = 1, name = main}的主线程中执行的。

采用异步执行方法(dispatch_async)的全局队列都在非主线程中执行的,这说明系统为这些队列开启了新线程,但并没有开启5个新线程,因为线程开多了也会占用系统(cpu、内存等)资源,而是开启了两条新线程({number = 4, name = (null)}、{number = 6, name = (null)})来异步执行这5个队列。个人理解线程的利用也采用“循环利用”原则,为某个采用异步方法队列开启的某个线程一旦被该队列用完,如果还有新的异步队列需要被处理,接着就拿这个线程来用。

总结:

获得全局队列:dispatch_queue_t queue = dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

采用同步方法(dispatch_sync(<dispatch_queue_t queue>, <^(void)block>))来执行这些队列(队列里还有任务):不会开启新线程,在主线程里执行。界面的更新在主线程中执行。

采用异步方法来(dispatch_async(<dispatch_queue_t queue>, <^(void)block>))执行这些队列(队列里还有任务):会开启新线程,线程“循环利用”,线程数:随机。

posted @ 2015-04-22 21:45  中峰  阅读(209)  评论(0编辑  收藏  举报