您的位置:首页 > 移动开发 > IOS开发

iOS多线程——GCD

2015-09-02 09:55 543 查看
//=============================

//GCD

1.四个关键术语:同步、异步、并发、串行

 

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

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

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

 

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

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

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

2.串行队列

获得方式一:

使用dispatch_queue_create函数创建串行队列

获得方式二:

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

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

使用dispatch_get_main_queue()获得主队列

3.并行队列

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

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

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此参数暂时无用,用0即可

 

4.GCD的常见使用

一。延迟执行

获取全局并发队列

计算任务执行的时间

二。一次性代码:整个程序运行过程中,只会执行一次

三。队列组

1.从网络上下载两张图片,把两张图片合并成一张最终显示在View上。

 

GCD概要/

1.什么是GCD

    GCD是异步执行任务的技术之一。

    脱字(caret)符号“^”:就是用了Blocks。

2.多线程编程

3.线程:1个CPU执行的CPU命令列为一条无分叉路径,一次只能执行一个命令。

4.妨碍主线程的执行就是阻塞。

5.dispatch_async(dispatch_get_main_queue(),^{}).仅此一行代码就能够让处理在主线程中执行。

6.让程序平行排队的特定任务,根据可用的处理资源,安排它们在任何可用的处理器上执行任务。

7.要执行的任务可以是一个函数或者Block。

8.底层是通过线程实现的,不过程序员可以不必关注实现的细节。

9.GCD中的FIFO队列称为dispatch queue,可以保证先进来的任务先得到执行。

10.dispatch_notify( m通知) 可以实现监听一组任务是否完成,完成后得到通知。

 

**************************************

GCD的API

1.Dispatch Queue:执行处理的等待队列。

1.1编程人员通过dispatch_async函数等API,在Block语法中记述想执行的处理并将其追加到Dispatch_Queue中。Dispatch Queue按照追加的顺序(先进先出FIFO,First-In-First-Out)执行处理。

1.2.在执行处理时存在两种Dispatch Queue:

一种是等待现在执行中处理的 Serial Dispatch Queue;——序列调度队列

另一种是不等待现在执行中处理的Concurent Dispatch Queue。——并发调度队列

                1.3.苹果官方对GCD的说明:开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。这句话用代码表示如下:

dispatch_async(queue,^{

    /*想执行的任务*/

}) ;  该源代码使用Block语法“定义想执行的任务”,通过dispatch_async函数“追加”赋值在变量queue的“Dispatch Queue”。仅这样就可使指定的Block在另一个线程中执行。

2.dispatch_queue_create

3.获取系统提供的Dispatch Queue。Main Dispatch Queue/Global Dispatch Queue

Global Dispatch Queue有4个优先级,分别是高优先级(H)

4.dispatch_set_target_queue

5.dispatch_after

在指定时间后执行处理的情况。

6.Dispatch Group

7.dispatch_barrier_async

8.

 

 

******************************************

GCD队列

1.队列(分三种)
dispatch_queue_t

//全局队列:(可能会开启多条线程,所有添加到主队列中的任务都是并发执行的,即异步执行,不同步。)

dispatch_get_global_queue(long identifier, unsigned long flags);
参数1:指定优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0    //默认值
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN


参数flags:可以指定为0

//主队列(所有添加到主队列中的任务都是在主线程中执行的)
dispatch_get_main_queue(void)

//串行队列:它是创建出来的(可能会开启一条线程,所有添加到串行队列中的任务都是顺序执行的)
dispatch_queue_create(const char *label, dispatch_queue_attr_tattr);
参数label:队列名称可以随意。
参数attr:两个常量值:DISPATCH_QUEUE_SERIAL:串行队列
                 DISPATCH_QUEUE_CONCURRENT:并发队列

 

 
//——————————————GCD任务的执行方式:同步和异步——————————————//

异步操作:

    1.dispatch_async  在其他线程执行任务,会开启新的线程。

    2.异步方法无法确定任务的执行顺序。

同步操作:

    1.dispatch_sync 在当前线程执行任务,不开启新的线程

    2.同步操作于队列无关

    3.同步方法会依次执行,能够决定任务的执行顺序

    4.更新界面UI时,最好使用同步方法

******************************************

三。GCD的实现

操作:用户界面更新、数据库访问、

我们现在关注的是对于某一个问题,我们是要明白的是:我们要完成什么功能,用什么方法实现(就是考虑它的运行机制,然后一步一步的来)。我们注重的是问题本身和代码的实现,而不是一大堆的理论。

 

dispatch_queue_t

    指定派发队列

 

 

 

 

 

//——————————————例子1——————————————//
- (void)gcdLoad
{

    //1.获取全局队列

    dispatch_queue_t quque = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    
    for (UIImageView *imageView  in _imageViewSet)
{

        //2.在全局队列异步调用此方法,加载并更新图像
        dispatch_async(quque, ^{
            NSLog(@"GCD:%@",[NSThread currentThread]);
            //随机获取图像
            NSInteger num = arc4random_uniform(17)+1;
            NSString *imageName = [NSString stringWithFormat:@"%li.jpg",num];
            UIImage *image = [UIImage imageNamed:imageName];//通常此处的image是从网络上获取的

            

            //3.设置图像,在主线程队列中,调用异步方法,设置UI

            dispatch_async(dispatch_get_main_queue(), ^{
                [imageView setImage:image];
            });
        });
    }

  

    

}

//——————————————例子2:在全局队列中异步调用任务——————————————//

注意:全局调度队列是有系统负责的,开发时不用考虑并发线程数量问题。
- (void)gcdDemo
{

    //1)全局队列.。

    dispatch_queue_t quque = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2)在队列中异步执行任务
    dispatch_async(quque, ^{

        NSLog(@"task 1 :%@",[NSThread currentThread]);
    });
    dispatch_async(quque, ^{

        NSLog(@"task 2 :%@",[NSThread currentThread]);
    });
    dispatch_async(quque, ^{

        NSLog(@"task 3 :%@",[NSThread currentThread]);
    });

}

//——————————————例子3:在串行队列中异步调用任务——————————————//
- (void)gcdDemo
{

    //串行队列

    dispatch_queue_t  queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);

    // 2)在队列中异步执行任务
    dispatch_async(queue, ^{

        NSLog(@"task 1 :%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{

        NSLog(@"task 2 :%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{

        NSLog(@"task 3 :%@",[NSThread currentThread]);
    });

}
打印结果:
    


三个task的number都一样,是在一个线程中调用的,并且是串行。

//===========================

//操作队列与分发队列的对比

为了减轻开发者的工作负担,苹果公司打造了两种关键的并发技术,直接植入了iOS和Mac OS X之中,这就是操作(operation)队列和分发(dispatch)队列。

操作队列: NSOperationQueue

操作队列是一种面向对象的运作方式,使用Objective-C的封装方式。简要来说,就是有一个队列对象(NSOperationQueue),其中容纳了多个操作对象(NSOperation、NSBlockOperation、NSInvocationOperation),这些操作会根据队列的配置来执行。对于自己所容纳的操作,操作队列对象会自动管理和控制其执行。

分发队列

1.分发队列实际上是一种基于C语言的解决方案,使用了一种新型的中央服务,名为GCD(Grand Central Dispatch,大型中央分发器)。

2.CGD就像一个集线器或者分发站,将多项操作分布到多个处理器上,它是构建于核心服务层之上的。

3.当GCD分发一个新线程时,它会根据当前可用资源进行判断,在这一个时刻哪个处理器最适合做这项工作,就会为线程选择该处理器。

4.使用GCD,可以建立3种不同类型的队列。

    串行队列:任务会按照添加的顺序,一个接一个地依次执行。在队列中的前一个任务执行完毕之前,下一个任务不会启动。这种队列非常适合于执行类似从互联网上下载文件这样的操作,然后再下载完毕之后再将其写入或者读到内存中。比如说,你不会希望在文件下载完毕之前就写入该文件。

    并发队列:任务会按照添加的顺序执行,但根据当时可用的资源情况,可以再前面的任务结束之前就启动下一个任务。这在执行一系列独立操作时很有用处,比如对多个图像实施滤镜操作,要对下一个图像进行操作,并不需要等到当前图像处理完毕之后。如果GCD认为有足够的资源来启动第二个任务,它就会自动执行这个操作。

    主分发队列:这个队列与应用程序的主循环是等同的。要记住:当你执行多线程操作时,用户界面只能在应用程序的主线程中进行修改。这样就可以保证用户的输入不会被某个后台线程所忽略。因此,如果你正在某个辅助队列中执行代码,而又需要在主线程中执行一个动作,就可以在主分发队列中添加一个任务,该任务会在应用程序的主运行循环中执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: