Grand Central Dispatch(GCD)包含语言特点、运行库和系统增强功能,它提供系统的、综合的改进,进而去支持并发代码在iOS和OSX多核硬件上的执行。

子系统、CoreFoundation和Cocoa APIs 已经都延伸去使用这些功能,进而帮助系统和你的应用程序运行地更快,更高效,而且提高响应能力。考虑到一个程序有效使用多核的困难性,更不要说在不同的计算机中使用不同数量的计算机内核或者多个应用程序环境中竞争核。CGC,一个在系统层面的操作,可以更好的适应所有运行程序的需要,以平衡的方式去匹配可用系统资源。

这个文档用来描述GCD 的API,它在Unix系统水平支持异步执行操作。你可以使用这些API来管理与文件描述符、Mach 端口、信号或者计时器的相互作用。在OS Xv10.7以及以后,你也可以使用GCD去处理常规目的的异步I/O操作。

GCD并不限制于系统级别的应用程序,但是在你使用它到更高级别的应用程序中之前,你应该考虑一下Cocoa提供的简单的函数是不是比GCD更简单去满足你程序的需求。

注意

当你在把CGD和fork系统调用混合适用的时候,如果一个进程GCD调用优先于fork调用,这样就是不安全的。指导成功调用exec或者相关函数之后才安全。

同步与异步

  • 同步请求:同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作,
  • 异步请求:异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然可以对UI进行操作,程序可以继续运行

使用GCD步骤

  • 创建任务,确定你要进行的操作
  • 将任务 添加到队列中,GCD会自动将任务从队列中取出(FIFO),放到相应的线程中执行

两个主要执行任务函数

  • 异步执行函数(开启新线程):void dispatch_async ( dispatch_queue_t queue, dispatch_block_t block );
  • 同步执行函数(不开启新线程):void dispatch_sync ( dispatch_queue_t queue, dispatch_block_t block );

队列类型

  • 并发队列:可以让多个任务并发执行,并发功能只有在异步函数下才有效。

  • 串行队列:任务一个接着一个执行。

  • 创建并发队列:

    GCD默认已经提供了全局的并发队列,功整个应用使用,我们不需要手动创建,只要使用dispatch_get_global_queue函数获得全局的并发队列。如需要创建,也可使用dispatch_queue_create创建,指定:dispatch_queue_create创建的第二个参数为:DISPATCH_QUEUE_CONCURRENT

  • 创建串行队列

    串行队列可以通过以下两种方式获得:

    • dispatch_queue_create创建(指定dispatch_queue_create创建的第二个参数为:DISPATCH_QUEUE_SERIAL)
    • 使用主队列dispatch_get_main_queue(),主队列是GCD自带的一种特殊的串行队列,放在主队列的任务都会在主线程中执行。

GCD对象和自动引用计数

当你使用OC编译器运行你的app时,所有的dispatch对象都是OC对象。同样的,当自动引用计数(ARC)允许时,dispatch对象的保持和释放都是自动的,就像其他OC对象一样。当ARC不允许时,使用dispatch_retain和dispatch_release函数(或者OC语言)去保持和释放你的dispatch对象。你不能使用Core Foundation retain/release函数去保持和释放dispatch对象。

在晚一些的的项目构建中,如果你需要在ARC允许的app中使用retain/release语法(为了维护与现有代码的兼容性),你可以禁用OC dispathc对象通过添加 -DOS_OBJECT_USE_OBJE=0到你的编译器标示中。

函数
  • dispatch_ get_main_queue

    • 返回与系统主线程相关的串行调度队列。
    • 声明

      dispatch_queue_t dispatch_get_main_queue ( void );
    • 返回值

      返回主队列。这个队列是为了在调用main之前,为了主线程而自动创建的。
    • 讨论

      主线程是系统自动创建的,它和你的应用程序主线程相关联。你的程序使用下面三个函数中的一个(仅一个)来调用主队列:

      • 调用dispatch_main
      • 在iOS调用UIApplicationMain或者在OS X调用NSApplicationMain.
      • 在主线程上使用CFRunLoopRef。

        和全局并发队列一起,调用dispathc_suspend,dispatch_resume,dispatch_set_context,调用这些都是没有影响的。

例子

主线程上调用异步

- (void)syncOnMainThread
{
NSLog(@"task2:%@",[NSThread currentThread]); dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
}); NSLog(@"task3:%@",[NSThread currentThread]);
}

输出结果:

死锁:使用同步函数在主队列执行,会造成线程死锁情况

- (void)testDeadLock
{
NSLog(@"task2:%@",[NSThread currentThread]); dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_sync(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
}); NSLog(@"task3:%@",[NSThread currentThread]);
}

之所以会造成死锁,是因为当使用dispatch_sync的时候是执行同步任务,会阻塞当前线程,而main_queue的的任务会被放到主线程执行,但主线程已经被阻塞了,所以block的任务不能被执行,它不完成,dispatch_sync就会一直阻塞主线程,造成死锁现象。

同步执行串行队列:不会开启新线程,按照顺序执行

- (void)syncChuanxing
{
dispatch_queue_t queue = dispatch_queue_create("gcd.queue", NULL);
//添加任务到队列中执行任务
dispatch_sync(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task2:%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task3:%@",[NSThread currentThread]);
}); }

执行结果:

在同步函数中执行并发任务:在主线程中按顺序执行,并发队列失去并发功能

- (void)syncBingfa
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加任务到队列中执行任务
dispatch_sync(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task2:%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task3:%@",[NSThread currentThread]);
}); }

执行结果:

异步函数在串行队列上执行:可见程序开启单个线程的顺序执行

- (void)asynChuanxing
{
//获得全局的并发队列
dispatch_queue_t queue =dispatch_queue_create("gcd.queue", NULL);
// dispatch_queue_t queue =dispatch_get_main_queue();
//添加任务到队列中执行任务
dispatch_async(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3:%@",[NSThread currentThread]);
});
}

执行结果:

异步函数在并行队列上执行

- (void)asynBingxing
{
//获得全局的并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加任务到队列中执行任务
dispatch_async(queue, ^{
NSLog(@"task1:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3:%@",[NSThread currentThread]);
});
}

执行结果:



每次执行的结果可能不一样

延时执行

- (void)deleayRun
{
//通常的延时执行
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
[self performSelector:@selector(runWith:) withObject:@"2" afterDelay:2.0];
}); //gcd函数执行
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0*NSEC_PER_SEC));
dispatch_after(when, queue1, ^{
[self runWith:1];
});
//上边的gcd函数执行和这个一样
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self runWith:2];
}); }
#pragma mark - RunMethod
- (void)runWith:(NSInteger)tag
{
NSLog(@"执行函数:%ld",(long)tag);
}

组队列

- (void)zuDuiLie
{
// 创建一个组
dispatch_group_t group = dispatch_group_create();
// 下载图片1
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"下载图片1:%@",[NSThread currentThread]);
});
// 下载图片2
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"下载图片2:%@",[NSThread currentThread]);
});
// group任务都执行完毕,再执行其他操作
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并图片
NSLog(@"开始合并图片:%@",[NSThread currentThread]);
});
}

执行结果:

附:

下边是2015年8月30日上9:50更新的。

1、 线程:1个CPU执行的CPU命令列为一条无分叉的路径即为一个线程。
2、dispatch_queue_create的作用是创建一个派遣队列,是串行队列。
3、dispatch_set_target_queue:变更生成的Dispatch_Queue的执行优先级要使用dispatch_set_target_queue函数。它有两个参数,第一个参数是指定要变更执行优先级的Dispatch Queue;第二个参数是指定要使用的执行优先级相同优先级的Global Dispatch Queue为第二个参数。
4、dispatch_after:延迟执行
5、dispatch_group_notify:是把多个处理全部结束后再执行结束处理。最后可以用dispatch_group_notify(group名称)执行结束处理。
6、dispatch_group_wait:等待全部处理执行结束。
7、dispatch_barrier_async:会等待追加到并发派遣队列上的并行执行的处理全部结束之后,再将制定的函数处理追加到并发派遣队列。(有点类似于addDepency)先处理前面的几个操作,然后遇到barrier后只执行1个barrier追加的处理,然后再继续执行后面的处理。
8、dispatch_apply:该函数按照指定的次序将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。
9、dispatch_suspend/dispatch_resume:用于有时候不希望执行以追加的处理。
10、dispatch_once:保证在应用程序执行中只执行一次指定处理。

GCD的更多相关文章

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

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

  2. iOS 多线程之GCD的使用

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

  3. 【swift】BlockOperation和GCD实用代码块

    //BlockOperation // // ViewController.swift import UIKit class ViewController: UIViewController { @I ...

  4. 修改版: 小伙,多线程(GCD)看我就够了,骗你没好处!

    多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系 ...

  5. GCD的相关函数使用

    GCD 是iOS多线程实现方案之一,非常常用 英文翻译过来就是伟大的中枢调度器,也有人戏称为是牛逼的中枢调度器 是苹果公司为多核的并行运算提出的解决方案 1.一次性函数 dispatch_once 顾 ...

  6. hdu1695 GCD(莫比乌斯反演)

    题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). 知识点: 莫比乌斯反演/*12*/ 线性筛求莫比乌 ...

  7. hdu2588 GCD (欧拉函数)

    GCD 题意:输入N,M(2<=N<=1000000000, 1<=M<=N), 设1<=X<=N,求使gcd(X,N)>=M的X的个数.  (文末有题) 知 ...

  8. BZOJ 2820: YY的GCD [莫比乌斯反演]【学习笔记】

    2820: YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1624  Solved: 853[Submit][Status][Discu ...

  9. BZOJ 2818: Gcd [欧拉函数 质数 线性筛]【学习笔记】

    2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4436  Solved: 1957[Submit][Status][Discuss ...

  10. GCD总结

    //用block只有两种:同步执行/异步执行(参数1:队列;参数二:任务) dispatch_async(dispatch_get_global_queue(0, 0),^{ });//异步在新的线程 ...

随机推荐

  1. 控制对话框风格的activity的显示大小与位置

    项目开发的需要,因为到现在项目接近完工,用户提出对条件筛选方式进行修改,为做到最小的改动实现用户的需求,各种百度,对于对话框风格大家普遍使用PopupWindow,但由于之前开发设计时使用的是acti ...

  2. 如何利用Python生成随机密码

    写了个程序,主要是用来检测MySQL数据库的空密码和弱密码的, 在这里,定义了三类弱密码: 1. 连续数字,譬如123456,在get_weak_num中实现 2. 连续字母,譬如abcdef,在ge ...

  3. 软件开发常用设计模式—单例模式总结(c++版)

    单例模式:就是只有一个实例. singleton pattern单例模式:确保某一个类在程序运行中只能生成一个实例,并提供一个访问它的全局访问点.这个类称为单例类.如一个工程中,数据库访问对象只有一个 ...

  4. 附录D 安装ZooKeeper

    D.1    安装ZooKeeper D.1.1   下载ZooKeeper ZooKeeper是Apache基金会的一个开源.分布式应用程序协调服务,是Google的Chubby一个开源的实现.它是 ...

  5. ZOJ Problem Set - 1350 The Drunk Jailer ac代码 memset

    这是一道很简单的题目,题目大概意思说下:就是有n个监狱(编号从1到n),第一次全部打开,第二次打开编号为2的倍数的,第三次打开编号为3的倍数的,以此类推...最后问你有几个监狱是打开的 题目中我使用了 ...

  6. Node.js Express 路由文件分类

    前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...

  7. Solr学习总结(五)SolrNet的基本用法及CURD

    上一篇已经讲到了Solr 查询的相关的参数.这里在讲讲C#是如何通过客户端请求和接受solr服务器的数据, 这里推荐使用SolrNet,主要是:SolrNet使用非常方便,而且用户众多,一直都在更新, ...

  8. Android 源码下载方法(Git 方式clone)

    Android源码对于Android开发者来说,迟早有一天你会用到的,所以就记录一下,分享给读者,希望对读者有用 这里需要使用到Git相关知识,不清楚的可以先阅读,了解的可以跳过 Git-Tortoi ...

  9. Django admin 权威指南(一)

    版本: Django 1.10 此部分由官方文档<6.5.1 The Django admin site>翻译而来. 6.5.1.1 概览 默认情况下,使用startproject的时候, ...

  10. 我对Backbone.js的一些认识

    backbone.js已经不是当前最流行的前端框架了,但是对于我而言,依然具有比较好的学习价值.虽然目前来说,react,vue等mvvm框架非常火热,但是感觉自身还不到去使用这种框架的层次.这些技术 ...