关于GCD的简单认识

最近再次看了一下GCD,之前也只是停留在简单使用一下其中函数的程度,现在多了一点理解,做个归纳。

其实使用GCD的函数,很容易注意到有一个词是经常出现的,就是:Dispatch。查了下,是派遣、分派的意思,我目前对于GCD的理解就是基于这个词。虽然它是多线程编程的一个方式,但是不需要我们直接的管理、操纵线程,而是通过把任务(方法、代码块等形式)给定到特定的队列(queue),然后这些队列会把这些任务派遣给各个线程,就好像有几个非常给力的办事员,只要把任务给他们,他们会把任务分配好、给到正确的线程里。我觉得核心的东西就是这些队列对于任务分配、派遣,而这个就是Dispatch的意思。相对于直接管理线程,GCD就是多了一些queue,而这些queue就是分派任务的,所以我认为这些队列和它们分派任务这个动作是GCD的关键之处(目前就领会到这个层次了……)。

所以就有两个部分需要理解:1、有哪些队列(queue)以及它们的性质          2、各种函数,通过它们可以在同一个队列中执行不同的操作,其实这就是影响了队列分派(dispatch)的一步。  总结说,就是选择什么队列、执行什么样的操作的问题。

1、队列:

队列的类型名为dispatch_queue_t,首先可分为系统自带和自定义两类。系统自带的有4个队列,首先是主队列,使用

dispatch_get_main_queue()

得到,然后是3个global queue,使用

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0)

得到,其中两个参数第一个是制定优先级,3个队列分别有高、中、下3种优先级,使用DEFAULT 的话,就是中,第二个参数暂不清楚。

自定义队列的构建通过:

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

第一个参数是使用一个字符串来标识这个队列,第二个参数是选择这个队列为串行还是并行。在串行队列里,一个任务必须执行完之后才会返回,即使使用的是dispatch_async 这个一步调用的方法;但是在并行队列里,使用dispatch_async 这样的异步方法是会立即返回的,程序会继续向下执行不会阻塞,而通过其他函数如dispatch_sync也可以实现类似 串行队列的效果,即必须这个代码块执行完才会继续向下执行。

2、关于各种函数:

GCD里面的函数几乎都是具有函数指针和block两种形式,函数名上面的区别就是使用函数指针的后缀多了一个_f,其实由此也可看出函数指针和block在功能上的相似了。

(1)首先最常用的就是:如dispatch_async了,实现异步调用,上段代码:

- (void)disptch_sync_test{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(queue, ^{
        sleep(2);             //线程沉睡2秒模拟该操作执行了一段时间
        NSLog(@"串行");
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"并行");
    });
    NSLog(@"结束");
}

执行结果是:

2014-10-12 14:32:12.047 GCD_Demo[763:41657] 结束
2014-10-12 14:32:14.048 GCD_Demo[763:41689] 并行
2014-10-12 14:32:14.048 GCD_Demo[763:41687] 串行

“结束”的输出在最前面,说明前面两个block里面的代码还没有执行结束,就运行到NSLog(@"结束")了。

和它相似的是dispatch_sync ,它会阻塞线程,当它执行完了才会让程序继续向下,例如将上例中的第一个函数修改下变为:

- (void)disptch_sync_test{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_sync(queue, ^{    //改了这里,少了个a
        sleep(2);
        NSLog(@"串行");
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"并行");
    });
    NSLog(@"结束");
}

运行结果就变为:

2014-10-12 14:37:14.928 GCD_Demo[825:44430] 串行
2014-10-12 14:37:14.929 GCD_Demo[825:44430] 结束
2014-10-12 14:37:16.930 GCD_Demo[825:44466] 并行

“串行”的输出在最前面,表明第一个block的代码必须执行完才返回,才会继续向下,而因为第二个函数没有修改,依然是异步调用,所以“结束”的输出又会在“并行”的前面。

(2)有时会有这种情况,比如有一个类的对象S的构建需要两个不同的参数,假设为A、B,它们各自都需要一段操作来获取,但是A和B之间是互不关联的,所以肯定会使用异步并发的去分别获取A和B,就可以同时的获取A、B,代码可能这些写:

- (void)disptch_sync_test{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"获取A"); //这里代表执行操作获取A
        //(11)
    });
    dispatch_async(queue, ^{
        sleep(4);
        NSLog(@"获取B");    //这里代表操作获取B
        //(22)
    });
    NSLog(@"使用A和B构建S");   //这里代表操作构建S
}

但实际是构建S的时候,A,B还在执行中,所以不行。那把构建S放到(11)位置一边跟着获取A执行,但是B又得不到,放到(22)位置去一样道理,那怎么办?比如:

- (void)disptch_sync_test{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    __block BOOL finish_A = NO,finish_B = NO;  //使用__block修饰,以便在block内部修改值

    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"获取A"); //这里代表执行操作获取A
        finish_A = YES;
        if (finish_A && finish_B) {
            [self constructS];
        }
        //(11)
    });
    dispatch_async(queue, ^{
        sleep(4);
        NSLog(@"获取B");    //这里代表操作获取B

        finish_B = YES;
        if (finish_A && finish_B) {
            [self constructS];
        }
        //(22)
    });
    //NSLog(@"使用A和B构建S");   //这里代表操作构建S
}

-(void )constructS{
    NSLog(@"使用A和B构建S");   //这里代表操作构建S
}

但是这样的操作台麻烦了,需要额外定义一些变量和方法,如果使用Dispatch
Group就可以很好解决了。例子如下:

- (void)disptch_sync_test{
    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, ^{
        sleep(2);
        NSLog(@"获取A"); //这里代表执行操作获取A
    });

    dispatch_group_async(group, queue, ^{
        sleep(4);
        NSLog(@"获取B");    //这里代表操作获取B
    });

    dispatch_group_notify(group, queue, ^{
        NSLog(@"使用A和B构建S");   //这里代表操作构建S
    });
}

我的理解是这里使用一个group把多个操作进行了一定程度的绑定,然后对于使用dispatch_group_async 调用的任务是异步执行,不需等它执行完,这样就同时获取A、B,但是使用dispatch_group_notify 执行的代码会等到dispatch_group_async 执行完才能执行,所以可以很好的解决上述情况下的需求,相对很简洁、一目了然。

(3)

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"XXX");
    });

可以指定在多少时间之后执行,相对NSTimer更简洁,如果你不是想做重复性的操作的话。貌似时间的精度相对NSTimer要好,因为见过解析视频帧的源码里是使用这个方法来确定下一帧的时间的,具体精度如何不清楚。

(4)

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_apply(10, queue, ^(size_t idx) {
        sleep(2);
        NSLog(@"XXXX %zu",idx);   //传入的参数是调用的次数序号
    });

可以用来多次的执行block里面的语句块。从输出可以看出,应该是采用了递归,具体怎么递归的,没看太懂。

(5)

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"XXXX");
    });

使用它可以保证block里面的代码在程序的生命周期里只会执行一次,所以经常用来构建单例。

时间: 2024-10-06 17:33:45

关于GCD的简单认识的相关文章

GCD的简单用法

/* 创建一个队列用来执行任务,TA属于系统预定义的并行队列即全局队列,目前系统预定义了四个不同运行优先级的全局队列,我们可以通过dispatch_get_global_queue来获取它们 四种优先级 DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND 不得已情况下可用dispatch_queue_c

iOS多线程GCD的简单使用

在iOS开发中,苹果提供了三种多线程技术,分别是: (1)NSThread (2)NSOperation (3)GCD 简单介绍一下GCD的使用. GCD全称 Grand Central Dispatch,可以称之为大中央调度.实际上GCD是管理着一个线程池,如何创建线程,如何回收线程,以及分配多少个线程,这些都是GCD来控制的.在开发中,程序员是不用操作线程的相关事情,程序员只需要把应该做的操作放到相应的队列里面即可. 一:自定义队列 GCD中有多种队列,其中自定义的队列有两种:串行队列和并行

关于ios多线程GCD的简单介绍

很久没写博客了,实在太忙了,没有时间写.现在终于空闲下来了,今天就给大家介绍下ios开发里GCD的用法. 刚开始学习的新手,或许对多线程很迷茫,那么什么是线程呢?其实很简单,不要想那么复杂. 1.我们通常知道进程,就是正在执行中的程序,每个进程有自己独立的内存空间,进程之间互相不干涉.(就比如你打开微信) 2.什么是线程?线程是进程执行的基本单元.进程中的任务是在线程中执行的,进程在启动后会自动蜕化为主线程(ios UI Main thread),然后在执行任务. 3.线程的串航执行,比如我要下

iOS开发GCD的简单使用

- (void)viewDidLoad { [super viewDidLoad]; // gcd 可以充分调用设备的 cpu 发挥最大性能,在 C 语言基础之上封装的 // dispatch_queue_t开辟一个线程 // DISPATCH_QUEUE_PRIORITY_DEFAULT设置优先级 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 在此线程里开启异

iOS多线程管理-Thread,NSOperation,GCD的简单用法

多线程 1.程序是一个可执行文件 2.进程是程序执行的一个操作实体 3.进程是线程的集合 4.多线程就是在一个程序(一个进程)中开启多条线路,为并发执行多个任务提供方便. 什么是线程? 1.进程当中并发执行的代码片段 2.线程是提高代码效率的一个手段 3.IOS中主要用于防止界面假死 4.线程是处理异步任务的主要手段 =============================== NSThread 1.+ (void)detachNewThreadSelector:(SEL)selector t

GCD的简单介绍

一)GCD 的使用方式 dispatch_async(dispatch_queue_t queue, dispatch_block_t block); async表明运行方式 queue则是你把任务交给那个线程队列来处理 block代表的是你要做的事情 //线程运行方式 dispatch_async 异步执行 dispatch_sync  同步执行 dispatch_delay 延迟执行 ... 二)处理任务对象 dispatch queue(线程队列) 一.dispatch_get_main_

iOS Grand Central Dispatch(GCD) 的简单理解

引言: GCD的全称是Grand Central Dispatch,是苹果在iOS4.0发布的一套处理并发运算方面的API.其用途是为了提高处理器多核运算的能力. GCD有点像NSOperationQueue,它们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行,但GCD比之NSOpertionQueue更底层更高效. GCD的工作原理: GCD的工作原理是让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务. 一个任务可以是一个函数(

[第2章]多线程:GCD的简单使用(2)——调度组

接着上篇 Dispatch Groups 介绍 Grouping blocks allows for aggregate synchronization. Your application can submit multiple blocks and track when they all complete, even though they might run on different queues. This behavior can be helpful when progress can

swift GCD的简单使用

回到主线程 DispatchQueue.main.async { // print("这里是主线程") } 延时执行 let deadline = DispatchTime.now() + 5.0 DispatchQueue.global().asyncAfter(deadline: deadline) { // print("这里是延迟做的事情") } 开启一个异步线程 DispatchQueue.main.async { print("开新异步线程执行