https://github.com/xufeng79x/GCDDemo

1.简介

介绍GCD的使用,介绍多种队列与同步异步多种情况下的组合运行情况。

2.基本使用步骤

如果使用GCD则一般也就两个步骤

1.创建/获取执行队列

2.同步或者异步在队列中执行任务 ,通常任务为一个block

3.队列与执行类型(同步或者异步)的组合运行情况

GCD的队列分为串行队列和并发队列,这两种队里都可以自行创建。

除了能够自行创建队列外,系统中已经存在了主队列和全局队列,这两个队列我们可以直接获取使用。

GCD的任务执行方式有分为同步和异步两种。所以根据队列类型和执行方式我们可以排列组合进行选择,下面我们将对这种组合

加以测试来探索他们的不同表现。

执行方式/队列类型 自建串行队列 自建并发队列 主队列  全局队列

同步

       

异步

       

3.1 自建串行队列+同步执行

/**
 *  串行+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,全部在当前线程中执行
 */
-(void) test1
{
    // 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_SERIAL);

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 同步方式启动任务
        dispatch_sync(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

执行结果:

-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] 完成!

总结:

/**
 *  串行+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,全部在当前线程中执行
 */

3.2 自建串行队列+异步执行

/**
 *  串行+异步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:开启新线程且只开启一个新线程,全部在新线程中执行
 */
-(void) test2
{
    // 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_SERIAL);

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 同步方式启动任务
        dispatch_async(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] 完成!
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}

总结:

/**
 *  串行+异步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:开启新线程且只开启一个新线程,全部在新线程中执行
 */

3.3 自建并发队列+同步执行

/**
 *  并发队列+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,全部在当前线程中执行
 */
-(void) test3
{
    // 创建队列
    dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_CONCURRENT);

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_sync(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] 完成!

总结:

/**
 *  并发队列+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,全部在当前线程中执行
 */

3.4 自建并发队列+异步执行

/**
 *  并发队列+异步方式执行任务
 *  任务顺序:无序
 *  线程启动方式:开启多个线程,在多个线程中可以同时执行多个任务
 */
-(void) test4
{
    // 创建队列
    dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_CONCURRENT);

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_async(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] 完成!
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}

总结:

/**
 *  并发队列+异步方式执行任务
 *  任务顺序:无序
 *  线程启动方式:开启多个线程,在多个线程中可以同时执行多个任务
 */

接下来我们来测试一下两个特殊的队列:主队列和全局队列

主队列:负责在主线程上调度任务,顺序执行其中任务。其中的任务不会运行与子线程,换句话说无论是同步还是异步都不会开子线程。

3.5 主队列+同步执行

/**
 *  主队列+同步方式执行任务
 *  任务顺序:卡死
 *  线程启动方式:卡死
 */
-(void) test5
{
    // 创建队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_sync(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

总结:

/**
 *  主队列+同步方式执行任务
 *  任务顺序:卡死
 *  线程启动方式:卡死
 */

3.6 主队列+异步执行

/**
 *  主队列+异步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,只在主线程中执行(需要等到主线程中当前任务完成后再执行后续任务,可观察到先打印“完成“)

*/
-(void) test6
{
    // 创建队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_async(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] 完成!
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}

总结:

/**
 *  主队列+异步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,只在主线程中执行(需要等到主线程中当前任务完成后再执行后续任务,可观察到先打印“完成”)
 */

3.7 全局队列+同步执行

/**
 *  全局队列+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,只在主线程中执行
 */
-(void) test7
{
    // 创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(, );

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_sync(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] execute task :  , name = main}
-- :::] 完成!

总结:

/**
 *  全局队列+同步方式执行任务
 *  任务顺序:先进先出
 *  线程启动方式:不开启新线程,只在主线程中执行
 */

3.8 全局队列+异步执行

/**
 *  全局队列+异步方式执行任务
 *  任务顺序:无序
 *  线程启动方式:开启多个新线程,不同任务可在不同线程中并发执行
 */
-(void) test8
{
    // 创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(, );

    // 循环调用,确定任务的放置于启动顺序
    ; i < ; i++)
    {
        // 启动任务
        dispatch_async(queue,^{
            NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]);
        });
    }

    NSLog(@"%@", @"完成!");
}

结果:

-- :::] 完成!
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}
-- :::] execute task :  , name = (null)}

总结:

/**
 *  全局队列+异步方式执行任务
 *  任务顺序:无序
 *  线程启动方式:开启多个新线程,不同任务可在不同线程中并发执行
 */

4.至此对于GCD的一般用法总结如下:

执行方式/队列类型 自建串行队列 自建并发队列 主队列  全局队列

同步

1.不开启新线程

2.先进先出顺序执行

1.不开启新线程

2.先进先出顺序执行

 卡死

1.不开启新线程

2.先进先出顺序执行

异步

1.开启新线程,且只开启一个新线程。

2.先进先出顺序执行,且只在新线程中执行

1.开启多个线程,任务可在多个线程中并发执行

2.无序执行 

1.不开启新线程,只在主线程中执行

2.先进先出顺序执行

1.开启多个线程,任务可在多个线程中并发执行

2.无序执行 

有此我们可以看出:

1.同步执行方式都不会新建线程。

2.当队列为串行队列,则在异步执行方式下也只会开启一个线程,因为队列性质决定,开启多个线程也是徒劳无功。

3.主队列只能在主线程下执行。

3.全局队列的表现和自建并发队列一致,所以平时可以直接使用全局队列。

5.更进一步

我们看到GCD中存在卡死的现象,那么什么时候回出现这种情况呢?下一篇博文[New learn]GCD的卡死现象分析研究继续分析研究。

[New learn]GCD的基本使用的更多相关文章

  1. [New learn]GCD的卡死现象分析研究

    https://github.com/xufeng79x/GCDDemo 1.简介 前接[New learn]GCD的基本使用,我们分析了GCD的一般使用方法,其中比较特殊的是在分析到主队列的时候发生 ...

  2. [New learn]GCD其他方法的使用

    https://github.com/xufeng79x/GCDDemo 1.简介 在前面的两篇博文中我介绍了GCD的一般使用方法和死锁的分析调查.本博文中继续讲解GCD的其他比较常用的几个使用方法. ...

  3. bzoj 2818: Gcd GCD(a,b) = 素数

    2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1566  Solved: 691[Submit][Status] Descript ...

  4. Multithreading annd Grand Central Dispatch on ios for Beginners Tutorial-多线程和GCD的入门教程

    原文链接:Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial Have you ever written a ...

  5. SPOJ PGCD 4491. Primes in GCD Table && BZOJ 2820 YY的GCD (莫比乌斯反演)

    4491. Primes in GCD Table Problem code: PGCD Johnny has created a table which encodes the results of ...

  6. [New learn] 设计模式思考

    本文是对上文[New learn] 设计模式的思考总结 1.大框架 无论应用使用多少种设计模式和技巧,此模式都是应用的大框架.下图为本项目的基本架构图: 1.上图中大框架为经典的MVC模式. 2.Co ...

  7. SPOJ4491. Primes in GCD Table(gcd(a,b)=d素数,(1&lt;=a&lt;=n,1&lt;=b&lt;=m))加强版

    SPOJ4491. Primes in GCD Table Problem code: PGCD Johnny has created a table which encodes the result ...

  8. Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

    OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...

  9. iOS 多线程之GCD的使用

    在iOS开发中,遇到耗时操作,我们经常用到多线程技术.Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列 ...

随机推荐

  1. [洛谷P4248][AHOI2013]差异

    题目大意:给一个长度为$n$的字符串,求: $$\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|-2\times lcp(suf_i, ...

  2. 洛谷 P3959 宝藏 解题报告

    P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 \(n\) 个深埋在地下的宝藏屋, 也给出了这 \(n\) 个宝藏屋之间可供开发的 \(m\) 条道路和它们的长度. 小 ...

  3. React组件通信

    1.父子通信 父 -> 子 props子 -> 父 回调函数,父组件通过props向子组件传递一个函数,子组件调用函数,父组件在回调函数中用setState改变自身状态 2.跨层级通信 1 ...

  4. luoguP1357 花园

    矩阵乘法优化dp 注意环形处理: 发现,对于一个初始状态s的方案数,就是填n次后,再回到自己的状态.期间都是合法的话,那么一定这个方案就合法. 和开始状态有关.所以先把状态转移矩阵的(n-m)乘出来. ...

  5. bzoj 2599 [IOI2011]Race 点分

    [IOI2011]Race Time Limit: 70 Sec  Memory Limit: 128 MBSubmit: 4768  Solved: 1393[Submit][Status][Dis ...

  6. HDU 4313树形DP

    Matrix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  7. 【c#】Tesseract-ocr 3.0.2 版本使用实例

    简介 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程.OCR技术非常专业,一般多是印刷. ...

  8. Linux中 设置apache,mysql 开机启动

    linux开启启动的程序一般放在/etc/rc.d/init.d/里面,/etc/init.d/是其软连接 mysql设为linux服务 cp /usr/local/mysql5/share/mysq ...

  9. Flask从入门到放弃1:路由app.route()

    Flask从入门到放弃1: Flask中的路由app.route(): 参考来源:http://python.jobbole.com/80956/ https://www.raspberrypi.or ...

  10. 适配器模式 C#

    适配器模式 将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. ● Target目标角色:该角色定义把其他类转换为何种接口,也就是我们的期望接 ...