一、GCD介绍
1.what is GCD?
Grand Central Dispatch 中枢调度器。用很简单的方式实现了极为复杂繁琐的多线程编程。异步执行任务的技术之一。
 
2.GCD存在于libdispatch.dylib库中。默认加载了这个库,在程序运行过程中会动态的加载这个库,不需手动导入。
 
3.开发者要做的只是定义想执行的任务并追加到适当的队列中。(1.定制任务(BLock代码块) 2.放到适当的队列中(Dispatch queue))。
 
4.相关术语解释
同步(Synchronous)、异步(Asynchronous)、并发(concurrent)、并行(Parallelism)、串行(Serial):
 
同步vs异步:描述当一个函数相对于任务完成。同步需要等任务完成后才返回;异步不需要等任务完成就返回。
串行vs并发:描述当前任务相对于其它任务被执行。任务串行执行就是每次只有一个任务被执行,任务并发执行就是在同一时间可以有多个任务被执行。
并发vs并行:都是同时处理多个任务的概念。并行指多个任务在同一时刻发生;并发指多个任务在同一时间间隔内发生。
并发:在操作系统中,并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
 
上下文切换(Context Switch):一个上下文切换指当你在单个进程里切换执行不同的线程时存储与恢复执行状态的过程。
 
二、队列
1.概念:
1)串行队列(Serial Dispatch Queue):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
2)并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效
???程序运行时,线程和进程,开多个线程,程序运行的生命周期
 
2.创建队列
1.通过dispatch_queue_create
第一个参数:队列的名字
第二个参数:队列的类型(NULL或Serial为串行队列,concurrent为并发队列)
dispatch_queue_t myQueue =
                 dispatch_queue_create("com.wq.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue =
                 dispatch_queue_create("com.wq.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
 
3.获取系统提供的
1)Main Dispatch Queue 主线程中执行,串行队列。
   dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
   
2)Global Dispatch Queue 并发队列。
dispatch_queue_t globalDispatchQueue =           
                 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
第一个参数:优先级(高->默认->低->后台)
第二个参数:留以后用的,暂时不用,设为0
 
3.队列知识点
 
三、一些方法
    //串行队列
    dispatch_queue_t queueSerial = dispatch_queue_create("jr", DISPATCH_QUEUE_SERIAL);
 
    //并行队列

dispatch_queue_t queueConcu = dispatch_queue_create("jr2", DISPATCH_QUEUE_CONCURRENT);

//1、循环多次使用

//(1)添加串行队列,同步执行。可以当for循环使用(在主线程中)

 
    dispatch_apply(3, queueSerial, ^(size_t t) {// 参数^(size_t),需要自己加一个^(size_t t),否则有问题
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%@", [NSThread currentThread]);
 
    });

//(2)添加并行队列,同步执行。可以当for循环使用(如果循环次数大于1,则开子线程)

 
    dispatch_apply(3, queueConcu, ^(size_t t) {// 参数^(size_t),需要自己加一个^(size_t t),否则有问题
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%@", [NSThread currentThread]);
 
    });
   

//(3)参数size_t的作用:打印的是0.1.2.3.。。的序号

 
    dispatch_apply(3, queueSerial, ^(size_t t) {
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%li == %@", t, [NSThread currentThread]);
 
    });   

//(4)以上都是在主线程中进行的。如果想在子线程中执行,需要这样做

 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 
        dispatch_apply(3, queueConcu, ^(size_t t) {
 
            [NSThread sleepForTimeInterval:1];
 
            NSLog(@"%li == %@", t, [NSThread currentThread]);
 
        });
 
    });
 

//2、分组(可以监听组内子线程是否全部都执行完成)

    dispatch_group_t group = dispatch_group_create();   
 
    dispatch_group_async(group, queueConcu, ^{
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%@", [NSThread currentThread]);
 
    });
 
    dispatch_group_async(group, queueConcu, ^{
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%@", [NSThread currentThread]);
 
    });
 
    dispatch_group_async(group, queueConcu, ^{
 
        [NSThread sleepForTimeInterval:1];
 
        NSLog(@"%@", [NSThread currentThread]);
 
    });
   
    dispatch_group_notify(group, queueConcu, ^{
 
        NSLog(@"----%@", [NSThread currentThread]);
 
    });
 
 

//3、延迟(写在这个块中的代码都是在主线程中执行的)

 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[NSThread sleepForTimeInterval:2];

NSLog(@"----%@", [NSThread currentThread]);

});

NSLog(@"33333%@", [NSThread currentThread]);

    timer = [NSTimer scheduledTimerWithTimeInterval:.5 target:self selector:@selector(touchesBegan) userInfo:nil repeats:YES];
   

//4.设置障碍(在同一队列中,只要添加了障碍,不管有没有创建多线程,他后边的任务都要跨国这个障碍,即等待这个障碍结束)

 
    dispatch_async(queueConcu, ^{
 
        NSLog(@"11111");
 
    });
   
    dispatch_barrier_async(queueConcu, ^{
 
        [NSThread sleepForTimeInterval:5];
 
    });
   
    dispatch_async(queueConcu, ^{
 
         NSLog(@"11111");
 
    });
 
    dispatch_async(queueConcu, ^{
 
        NSLog(@"11111");
 
    });
    
    

//5、让代码只执行一次

 
    static dispatch_once_t oneToken;
 
    dispatch_once(&oneToken, ^{
 
        NSLog(@"=======");
 
    });
 
四、注意事项
 
1.dispatchbarrier\(a)sync只在自己创建的并发队列上有效,在全局(Global)并发队列、串行队列上,效果跟dispatch_(a)sync效果一样。既然在串行队列上跟dispatch_(a)sync效果一样,那就要小心别死锁!
 
2.dispatch_after只是延时提交block,并不是延时后立即执行。
 
3.dispatch_suspend,dispatch_resume提供了“挂起、恢复”队列的功能,简单来说,就是可以暂停、恢复队列上的任务。但是这里的“挂起”,并不能保证可以立即停止队列上正在运行的block。
 
4.dispatch_apply的作用是在一个队列(串行或并行)上“运行”多次block,其实就是简化了用循环去向队列依次添加block任务。dispatch_apply会“等待”其所有的循环运行完毕才往下执行。
//创建异步串行队列
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_CONCURRENT);
//运行block3次
dispatch_apply(3, queue, ^(size_t i) {
    NSLog(@"apply loop: %zu", i);
});
//打印信息
NSLog(@"After apply");
 
明明是提交到并发队列去运行,但是“After apply”居然在apply loop:0/1/2后打印,也就是说,dispatch_apply将外面的线程(main线程)“阻塞”了!
 
4.dispatch_sync导致的死锁。//在main线程使用“同步”方法提交Block,必定会死锁
5.一定要避免dispatch_apply的嵌套调用。会导致死锁。
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
        
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
    
    //再来一个dispatch_apply!死锁!      
dispatch_apply(3, queue, ^(size_t j) {
NSLog(@"apply loop inside %zu", j);
});
});

GCD基础的更多相关文章

  1. iOS 开发之 GCD 基础

    header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...

  2. iOS开发之GCD基础

    重新回顾.学习GCD.Block.先贴出一篇不错的讲解GCD基础使用的文章 原文地址:http://blog.csdn.net/aolan1108/article/details/17283415 做 ...

  3. GCD基础知识总结

    iOS三种多线程编程技术: 1.NSThread 2.NSOperation 3.GCD(Grand Central Dispatch) 从上到下,抽象度层次从低到高,抽象度越高的使用越简单,也是Ap ...

  4. 多线程基础(六)GCD基础

    更多值得学习的GCD知识,可以学习: Grand Central Dispatch (GCD) Reference GCDObjC 1.GCD的基本概念     什么是GCD 全称是Grand Cen ...

  5. iOS GCD基础篇 - 同步、异步,并发、并行的理解

    1.关于GCD - GCD全称是Grand Central Dispatch  - GCD是苹果公司为多核的并行运算提出的解决方案  - GCD会自动利用更多的CPU内核(比如双核.四核)  - GC ...

  6. GCD基础知识

    并行和并发 在英文世界里,「并行」和「并发」的区别比较清晰,「并行」对应parallelism,「并发」对应concurrency:但在中文世界里二者仅一字之差,两个概念非常容易弄混淆: 各种资料对「 ...

  7. IOS GCD定时器

    提到定时器,NStimer肯定是我们最为熟悉的. 但是NStimer有着很大的缺点,并不准确. 通俗点说,就是它该做他的事了,但是由于其他事件的影响,Nstimer会放弃他应该做的. 而GCD定时器, ...

  8. iOS GCD中级篇 - dispatch_group

    1.关于dispatch_group 把一组任务提交到队列中,这些队列可以不相关,然后监听这组任务完成的事件. 最常见的几个方法: 1.dispatch_group_create创建一个调度任务组 2 ...

  9. [BZOJ 2257][JSOI2009]瓶子和燃料 题解(GCD)

    [BZOJ 2257][JSOI2009]瓶子和燃料 Description jyy就一直想着尽快回地球,可惜他飞船的燃料不够了. 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子 ...

随机推荐

  1. Shell脚本 curl获取必应每日壁纸(Mac OS)

    Mac上Safari不能下载壁纸,遇到好看的很想用作壁纸.写了一小段脚本用来拉取网页图片. curl: -sS 参数用来取消下载状态显示 grep 首先把含有图片网址的行提取了出来,针对这一行再做se ...

  2. jqueryUI之datepicker日历插件的介绍和使用

    jQuery UI很强大,其中的日期选择插件Datepicker是一个配置灵活的插件.我们可以自定义其展示方式,包括日期格式.语言.限制选择日期范围.添加相关按钮以及其它导航等.

  3. Eclipse中快速定位

    Eclipse中快速定位 选中项目,ctrl+h 一.目标 查找如下的页面属于哪个activity 二.步骤 1.查找关键字 上述页面中“点我”两个字比较显眼,我们可以去android项目中搜索出现“ ...

  4. IntelliJ IDEA 返回上次编辑(鼠标停留)的地方

    idea默认的是 : Ctrl + Alt + 左箭头,与笔记本的 旋转屏幕冲突: 找到: 我更改成了: Ctrl + CapsLock :暂时没发现冲突.

  5. WPF:理解TileBrush(ImageBrush,DrawingBrush和VisualBrush)

    ImageBrush:利用图像绘制区域 ImageBrush 是一种将自身内容定义为图像的 TileBrush,图像通过它的 ImageSource 属性指定. 您可以控制图像的拉伸.对齐和平铺方式, ...

  6. vim 的寄存器

    If you've been following my series on Vim, it should be clear now that Vim has a pretty clear philos ...

  7. hdu4347The Closest M Points kdtree

    kdtree讲解: https://blog.csdn.net/qing101hua/article/details/53228668 https://blog.csdn.net/acdreamers ...

  8. 1-18 编译安装内核支持ntfs文件系统

    大纲: 源码编译Linux内核 使用Linux内核模块 实战:编译一个NTFS内核模块,实现Linux挂载NTFS文件系统并实现读写功能 =============================== ...

  9. 1-12 RHEL7-find命令的使用

    1.文件查找findfind命令是在目录结构中,搜索文件,并执行特定的操作find命令提供了相当多的查找条件,功能很强大 2.格式usage:find pathname -options[-print ...

  10. .Net使用Redis详解之ServiceStack.Redis(7)

    Net使用Redis详解之ServiceStack.Redis(七) 序言 本篇从.Net如何接入Reis开始,直至.Net对Redis的各种操作,为了方便学习与做为文档的查看,我做一遍注释展现,其中 ...