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


总结:不会开启新线程



原文地址:https://www.cnblogs.com/AbeDay/p/5026953.html