关闭

IOS 多线程-GCD学习总结

标签: ios开发多线程gcd
172人阅读 评论(0) 收藏 举报
分类:

最近看了很多关于IOS多线程编程的知识,现总结如下,大家互相学习,如有错误,还请各位指点。

什么是GCD?

Grand Central Dispatch(GCD)是异步执行任务的技术,苹果公司将线程管理的任务在系统级别实现,对程序员是透明的,程序员只需要将任务提交给Dispatch Queue,GCD就可以给任务分配空闲的线程,从而执行任务。

多线程编程的好处这里就不多说了,在手机设备这类硬件受限的系统中,充分利用多线程能很好的提升应用的性能,下面是一个简单的例子:

<span style="font-size:14px;">   //将下载图片的操作放在子线程中执行,不会阻塞主线程
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
        
        NSData *data = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:url]];
        UIImage *image = [[UIImage alloc]initWithData:data];
        if (image != nil) {
            //[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
            // 将更新图片UI的任务提交给主线程队列中执行
            dispatch_async(dispatch_get_main_queue(),^(void){
                self.imageView.image = image;
            });
        }else{
            NSLog(@"download image error!!!");
        }
    });</span>
例子中将从网络中下载一张图片放在主页中,如果不加入多线程操作,那么在下载图片的过程中,应用将不会响应任何操作。

使用GCD

程序员利用GCD实现多线程编程,只需要两步操作:

  • 生成特定的Dispatch Queue;
Dispatch Queue:队列负责管理程序员提交的任务,GCD队列利用FIFO(先进先出)的方式来处理任务。队列既可以是串行的(Serial Dispatch Queue),也可以是并发的(Concurrent Dispatch Queue),串行队列每次只能处理一个任务,前一个任务执行完才能执行下一个;而在并发队列中可以同时执行多个任务,不必等待某一个任务执行完,但是并行执行的处理数量取决于当前系统的状态,即iOS和OS X 基于Dispatch Queue中的处理任务数,CPU核数以及CPU负载等当前系统的运行状态和决定并发队列中并行执行的线程数量。这里所说的并行执行,就是使用多个线程同时执行多个任务。
队列的底层会实现一个线程池,串行队列的线程池只有一个线程,并发队列的线程池会有多个线程。
  • 将要完成的任务提交给第一步生成的dispatch Queue;
任务就是用户提交给队列的工作单元,主要有Block和函数两种方式。

创建队列的方法

  • dispatch_queue_create
函数原型:dispatch_queue_t  dispatch_queue_create(const  char *label,dispatch_queue_attr_t attr):第一个参数是队列的标签,主要用来调试时用;第二个参数可以控制创建的是串行(null或者DISPATCH_QUEUE_SERIAL)还是并发队列(DISPATCH_QUEUE_CONCURRENT)。
这里大家注意,虽然串行队列每次只能执行一个任务,但是用此函数可以生成任意多个队列,也就是说当生成多个串行队列,各个串行队列将并行执行,但是建立多个串行队列会对系统造成很大的负担,因为会引起大量的上下文切换。虽然也可以建立多个并发队列,但是并发队列底层的线程池会根据系统的状态实时的调整线程的数量,所以影响不大,而且也得不偿失。希望大家好好考虑。
另外尽管有ARC内存管理技术,但是生成的Dispatch Queue 必须由程序员负责释放,因为Dispatch Queue 并没有像Block那样具有作为OC对象来处理的技术。利用dispatch_release(myCreateDispatchQueue),来释放建立的队列。
  • Main Dispatch Queue
函数原型:dispatch_queue_t  dispatch_get_main_queue(void),获取应用主线程所关联的串行队列,就像上面的代码中一样,将更新应用UI的动作放到主线程中执行,这也是IOS系统规定的操作。
  • Global Dispatch Queue
函数原型:dispatch_queue_t dispatch_get_global(long priority,unsigned long flags),根据指定的优先级,标志(现在还未使用,传入0即可)来获取系统全局的并发队列。第一个参数有4个指定的优先级DISPATCH_QUEUE_PRIORITY_HIGH(2),DISPATCH_QUEUE_PRIORITY_DEFAULT(0),DISPATCH_QUEUE_PRIORITY_LOW(-2),DISPATCH_QUEUE_PRIORITY_BACKGROUND。那么在队列底层的线程池是将各自队列的优先级作为线程的优先级来处理任务的,所以在提交任务的时候应该选择合适优先级的队列。

提交任务的API

提交任务的API通常有两个版本:一个接受代码块Block作为参数,一个是接受函数作为参数的版本。在这里仅罗列几个常用的API,其他的还请大家参考官方文档。
  • void  dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>); 将代码块以异步的方式提交给队列。
  • void dispatch_async_f(<#dispatch_queue_t queue#>, <#void *context#>, <#dispatch_function_t work#>);将函数以异步的方式提交给制定队列。
  • void dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>);将代码块以同步的方式提交给队列,如果以同步的方式提交1,2两个任务,那么会先执行完任务1,然后再执行任务2.
  • void dispatch_sync_f(<#dispatch_queue_t queue#>, <#void *context#>, <#dispatch_function_t work#>);提交函数任务,就不再细说。
  • void dispatch_after(<#dispatch_time_t when#>, <#dispatch_queue_t queue#>, <#^(void)block#>); 注意,该函数并不是在指定时间后执行处理,而只是在指定时间后追加任务到队列,如果队列中的任务数很多,那么开始执行的时间可能会更长。所以这个时间只是一个模糊值。
  • void dispatch_group_async(<#dispatch_group_t group#>, <#dispatch_queue_t queue#>, <#^(void)block#>);只有当提交到group 队列中的任务全部执行完才能执行下面的任务。
  • void dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t queue#>, <#^(size_t)block#>);将代码块异步的提交给队列,该队列底层的线程池会执行该代码块指定次数。
  • void dispatch_once(<#dispatch_once_t *predicate#>, <#^(void)block#>);该代码块在某个生命周期内仅执行一次。

GCD 实现

GCD的dispatch Queue 实现多线程非常方便,那么它的底层实现原理又是怎样?根据他的使用方法,我们可以想到以下几点:
  • 用于管理追加Block或者函数任务的C语言实现的FIFO队列
  • Atomic函数中实现的用于排他控制的轻量级信号
  • 用于管理线程的C语言层实现的一些容器
通常应用程序中编写的线程管理用的代码需要在系统级别实现,这样对程序员透明,而且管理效率肯定比程序员实现的线程管理要高的多。这里只是简单的思考以下,以后再来补充。


PS:以上内容有自己总结的也有参考的,所以如有雷同,纯属正常,一起学习而已。













dispatch_sync_f(<#dispatch_queue_t queue#>, <#void *context#>, <#dispatch_function_t work#>)
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:32092次
    • 积分:529
    • 等级:
    • 排名:千里之外
    • 原创:17篇
    • 转载:31篇
    • 译文:0篇
    • 评论:0条