zoukankan      html  css  js  c++  java
  • iOS开发多线程篇—GCD介绍

    iOS开发多线程中的GCD介绍


    转载自:http://www.cnblogs.com/wendingding/p/3806821.html

    什么是GCD?

    GCD-(Grand Central Dispatch)是Apple公司开发的一种技术。这种技术可以在多核硬件中并发处理多个任务。也可以说,GCD是多线程的一种扩展和替代技术。GCD 在Mac OS x 10.6 和 IOS 4.0 以后开始支持.GCD 的核心是分派队列。不论在 iOS 还是 Max OS X 分派队列,正如我们快看到的是 由位于主操作系统的 GCD 来管理的线程池。你不会直接与线程有工作关系。你只在分派队列上工作,将任务分派到这个队列上并要求队列来调用你的任务。GCD 为运行任务提供了几个选择:同步执行、异步执行和延迟执行等。

     

    GCD有什么特点:

    1.GCD可以在充分利用多核硬件并发处理多个任务。也就是说,效率高。

    2.GCD 的API提供了很多同步,异步,分组等正对多任务,同步,异步的操作。也就是一种比多线程还要牛X

    写的技术。

    3.使用GCD我们可以更容易的利用多核处理器并行处理任务。

    4.GCD 使用后不用程序去管理线程的开闭,GCD会在系统层面上去动态检测系统状态,开闭线程。

     

    什么时候使用多线程?

             在实际开发中我们常常把那些比较耗时且与UI无关的操作放到非主线程中去执行,避免这些耗时操作阻塞主线程导致界面操作起来很卡。比如:加载网络数据、本地存储、读取、更新大量数据这些情况都应该使用多线程。

    我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作


    任务和队列

    GCD中有2个核心概念

    (1)任务:执行什么操作

    (2)队列:用来存放任务

     

    GCD的使用就2个步骤

    (1)定制任务

    (2)确定想做的事情

     

    将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行

    提示:任务的取出遵循队列的FIFO原则:先进先出,后进后出

    执行任务

    1.GCD中有2个用来执行任务的函数

    说明:把右边的参数(任务)提交给左边的参数(队列)进行执行。

    (1)用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_tblock);

    参数说明:

    queue:队列

    block:任务

     

    (2)用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

    2.同步和异步的区别

    同步:在当前线程中执行

    异步:在另一条线程中执行


    队列

    1.队列的类型

    GCD的队列可以分为2大类型

    (1)并发队列(ConcurrentDispatch Queue)

    可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效

     

    (2)串行队列(SerialDispatch Queue)

    让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

                         

    2.补充说明

    有4个术语比较容易混淆:同步、异步、并发、串行

    同步和异步决定了要不要开启新的线程

    同步:在当前线程中执行任务,不具备开启新线程的能力

    异步:在新的线程中执行任务,具备开启新线程的能力

     

    并发和串行决定了任务的执行方式

    并发:多个任务并发(同时)执行

    串行:一个任务执行完毕后,再执行下一个任务

     

    3.串行队列

    GCD中获得串行有2种途径

    (1)使用dispatch_queue_create函数创建串行队列

    dispatch_queue_t  dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); // 队列名称, 队列属性,一般用NULL即可

    示例:

    dispatch_queue_t queue =dispatch_queue_create("wendingding", NULL); // 创建

    dispatch_release(queue); // 非ARC需要释放手动创建的队列

     

    (2)使用主队列(跟主线程相关联的队列)

    主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行

    使用dispatch_get_main_queue()获得主队列

    示例:                         

    dispatch_queue_t queue =dispatch_get_main_queue();

     

    4.并发队列

    GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建

    使用dispatch_get_global_queue函数获得全局的并发队列

    dispatch_queue_tdispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned longflags); // 此参数暂时无用,用0即可

    示例:

    这个参数是留给以后用的,暂时用不上,传个0。

    第一个参数为优先级,这里选择默认的。获取一个全局的默认优先级的并发队列。

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

    说明:全局并发队列的优先级

    #define DISPATCH_QUEUE_PRIORITY_HIGH 2// 高

    #define DISPATCH_QUEUE_PRIORITY_DEFAULT0 // 默认(中)

    #define DISPATCH_QUEUE_PRIORITY_LOW(-2) // 低

    #defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台

    5.各种队列的执行效果



    GCD的函数介绍

    这里介绍GCD的几个常用的函数

    1.dispatch_apply

    执行某个代码片段N次。

    dispatch_apply(5, globalQ, ^(size_t index) {
    // 执行5次
    });
    

    2. dispatch_once

    执行某个代码片段1次

    // dispatch_once这个函数,它可以保证整个应用程序生命周期中某段代码只被执行一次!	
    	static dispatch_once_t onceToken;  
    	    dispatch_once(&onceToken, ^{  
    	        //代码被执行一次
    	    });  
    

    3.dispatch_after

    推迟一段时间之后,执行代码片段

    //有时候我们需要等个几秒钟然后做个动画或者给个提示,这时候可以用dispatch_after这个函数:
    double delayInSeconds = 2.0;  
    	    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);  
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  
    	        // code to be executed on the main queue after delay  
    	    });  
    


    4.dispatch_group
    让后台2个线程并行执行,然后等2个线程都结束后,再汇总执行结果。这个可以用dispatch_group, dispatch_group_async 和dispatch_group_notify来实现,示例如下:

    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), ^{
          // 汇总结果
     });


    下面是dispatch_group的使用示范

    -(void) groupUSE{
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_group_t group = dispatch_group_create();
        
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"第一个任务");
        });
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"第二个任务");
        });
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"第三个任务");
        });
        
        dispatch_group_notify(group, queue, ^{
            NSLog(@"汇总任务");
        });
        
    }


    代码示范

    为了更好的理解这个多线程GCD的调用,这里附上一份代码,便于理解和加深记忆。

    (1)用异步函数往并发队列中添加任务

    //
    //  YYViewController.m
    //  08-GCD基本使用
    //
    //  Created by apple on 14-6-24.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYViewController.h"
    
    @interface YYViewController ()
    
    @end
    
    @implementation YYViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        //1.获得全局的并发队列
       dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //2.添加任务到队列中,就可以执行任务
        //异步函数:具备开启新线程的能力
        dispatch_async(queue, ^{
            NSLog(@"下载图片1----%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
    //打印主线程
        NSLog(@"主线程----%@",[NSThread mainThread]);
        
    }
    
    @end


    总结:同时开启三个子线程

    (2)用异步函数往串行队列中添加任务

    //
    //  YYViewController.m
    //  09—GCD基本使用2
    //
    //  Created by apple on 14-6-24.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYViewController.h"
    
    @interface YYViewController ()
    
    @end
    
    @implementation YYViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        //打印主线程
        NSLog(@"主线程----%@",[NSThread mainThread]);
        
        //创建串行队列
        dispatch_queue_t  queue= dispatch_queue_create("wendingding", NULL);
        //第一个参数为串行队列的名称,是c语言的字符串
        //第二个参数为队列的属性,一般来说串行队列不需要赋值任何属性,所以通常传空值(NULL)
        
        //2.添加任务到队列中执行
        dispatch_async(queue, ^{
            NSLog(@"下载图片1----%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
        
        //3.释放资源
    //    dispatch_release(queue);
    }
    
    @end


    总结:会开启线程,但是只会开启一个线程

    3)用同步函数往并发队列中添加任务

    //
    //  YYViewController.m
    //  10-CGD基本使用3
    //
    //  Created by apple on 14-6-24.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYViewController.h"
    
    @interface YYViewController ()
    
    @end
    
    @implementation YYViewController
    /**
     *  用同步函数往并发队列中添加任务
     */
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        //打印主线程
        NSLog(@"主线程----%@",[NSThread mainThread]);
        
        //创建串行队列
        dispatch_queue_t  queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        
        //2.添加任务到队列中执行
        dispatch_sync(queue, ^{
            NSLog(@"下载图片1----%@",[NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"下载图片3----%@",[NSThread currentThread]);
        });
    }
    
    @end


    总结:不会开启新线程,并发队列失去并发功能

    4)用同步函数往串行队列中添加任务

    //
    //  YYViewController.m
    //  11—CGD基本使用4
    //
    //  Created by apple on 14-6-24.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYViewController.h"
    
    @interface YYViewController ()
    
    @end
    
    @implementation YYViewController
    
    
    /**
     *用同步函数往串行队列中添加任务
     */
    - (void)viewDidLoad
    {
        [super viewDidLoad];
         NSLog(@"用同步函数往串行队列中添加任务");
        //打印主线程
        NSLog(@"主线程----%@",[NSThread mainThread]);
        
        //创建串行队列
        dispatch_queue_t  queue= dispatch_queue_create("wendingding", NULL);
        
        //2.添加任务到队列中执行
        dispatch_sync(queue, ^{
            NSLog(@"下载图片1----%@",[NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"下载图片2----%@",[NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"下载图片3----%@",[NSThread currentThread]);
        });
    }
    
    @end


    总结:不会开启新线程



  • 相关阅读:
    第10组 Alpha冲刺 (4/6)(组长)
    Android菜鸟成长记10 ListVew
    Android菜鸟成长记3activity类
    Android菜鸟成长记2内部类
    Android菜鸟成长记7 Android的五大布局
    Android菜鸟成长记4button点击事件
    Android菜鸟成长记8 布局实践(微信界面的编写)
    Android菜鸟成长记9 selector的用法
    Android菜鸟成长记6 网络连接的检查
    Android菜鸟成长记5ADB和sqllite
  • 原文地址:https://www.cnblogs.com/AbeDay/p/5026953.html
Copyright © 2011-2022 走看看