Blocks与Dispatch Queue的使用
block是什么
block是一个C level的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似。用于回调函数的地方。两个对象间的通讯。实现轻量级的“代理”。
blocks和C语言函数指针的区别

如何调用blocks
调用block和C语言函数指针的调用一模一样


如何在 block 中修改外部变量?????
考虑到 block 的目的是为了支持并行编程,对于普通的 local 变量,我们就不能在 block 里面随意修改(原因很简单,block 可以被多个线程并行运行,会有问题的),而且如果你在 block 中修改普通的 local 变量,编译器也会报错。那么该如何修改外部变量呢?有两种办法,第一种是可以修改 static 全局变量;第二种是可以修改用新关键字 __block 修饰的变量。
__block关键字
一个Block的内部是可以引用自身作用域外的变量的,包括static变量,extern变量或自由变量(定义一个变量的时候,如果不加存储修饰符,默认情况下就是自由变量auto,auto变量保存在stack中的,除了auto之外还存在register,static等存储修饰符),
对于局部变量,在block中是只读的。在引入block的同时,还引入了一种特殊的关键字__block,用此声明一个局部变量可以被函数块修改。
实例:
void(^aBlock)(void) = 0; // 声明一个block
aBlock = ^(void){ // 给block赋值
NSLog(@"this is a block.");
};
aBlock(); // 执行block
上面我们介绍了 block 及其基本用法,但还没有涉及并行编程。 block 与 Dispatch Queue 分发队列结合起来使用,是 iOS 中并行编程的利器。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
// 创建一个串行分发队列
dispatch_queue_t queue = dispatch_queue_create("studyBlocks", NULL);
// 将一个 block 任务加入到其中并行运行. 这样 block 就会在新的线程中运行,直到结束返回主线程
// 加入 dispatch_queue 中的 block 必须是无参数也无返回值的
dispatch_async(queue, ^(void){
int sum = 0;
for (int i = 0; i<100; i++) {
sum += i;
}
NSLog(@"sum:%d",sum);
});
dispatch_release(queue);
[pool drain];
1、dispatch_queue_t 类型 的定义如下:
typedef void (^dispatch_block_t)( void);
这意味着加入 dispatch_queue 中的 block 必须是无参数也无返回值的。
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
该函数创建分发队列dispatch_queue。带有两个参数:一个用于标识 dispatch_queue 的字符串;一个是保留的 dispatch_queue 属性,将其设置为 NULL 即可。
来获得全局的 dispatch_queue,参数 priority 表示优先级,值得注意的是:我们不能修改该函数返回的 dispatch_queue。例如:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[[self captureManager] session] startRunning];
});
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
该函数将一个 block 加入一个 dispatch_queue,这个 block 会再其后得到调度时,并行运行。
相应的 dispatch_sync 函数就是同步执行了,一般很少用到。比如上面的代码如果我们修改为 dispatch_sync,那么就无需编写 flag 同步代码了。
我们可以将许多 blocks 用 dispatch_async 函数提交到到 dispatch_queue 串行运行。这些 blocks 是按照 FIFO(先入先出)规则调度的,也就是说,先加入的先执行,后加入的一定后执行,但在某一个时刻,可能有多个 block 同时在执行。
在上面的例子中,我们的主线程一直在轮询 flag 以便知晓 block 线程是否执行完毕,这样做的效率是很低的,严重浪费 CPU 资源。我们可以使用一些通信机制来解决这个问题,如:semaphore(信号量)。 semaphore 的原理很简单,就是生产-消费模式,必须生产一些资源才能消费,没有资源的时候,那我就啥也不干,直到资源就绪。
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
initData();
// Create a semaphore with 0 resource
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
// create dispatch semaphore
dispatch_queue_t queue = dispatch_queue_create("StudyBlocks", NULL); dispatch_async(queue, ^(void) {
int sum = 0;
for(int i = 0; i < Length; i++)
sum += data;
NSLog(@" >> Sum: %d", sum);
// signal the semaphore: add 1 resource
dispatch_semaphore_signal(sem);
});
// wait for the semaphore: wait until resource is ready.
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);
dispatch_release(queue);
[pool drain];
下面我们来看一个按照 FIFO 顺序执行并用 semaphore 同步的例子:先将数组求和再依次减去数组。
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
initData();
__block int sum = 0;
// Create a semaphore with 0 resource
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block dispatch_semaphore_t taskSem = dispatch_semaphore_create(0);
// create dispatch semaphore
dispatch_queue_t queue = dispatch_queue_create("StudyBlocks", NULL);
dispatch_block_t task1 = ^(void) {
int s = 0;
for (int i = 0; i < Length; i++)
s += data;
sum = s;
NSLog(@" >> after add: %d", sum);
dispatch_semaphore_signal(taskSem);
};
dispatch_block_t task2 = ^(void) {
dispatch_semaphore_wait(taskSem, DISPATCH_TIME_FOREVER);
int s = sum;
for (int i = 0; i < Length; i++)
s -= data;
sum = s;
NSLog(@" >> after subtract: %d", sum);
dispatch_semaphore_signal(sem);
};
dispatch_async(queue, task1);
dispatch_async(queue, task2);
// wait for the semaphore: wait until resource is ready.
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(taskSem);
dispatch_release(sem);
dispatch_release(queue);
[pool drain];
在上面的代码中,我们利用了 dispatch_queue 的 FIFO 特性,确保 task1 先于 task2 执行,而 task2 必须等待直到 task1 执行完毕才开始干正事,主线程又必须等待 task2 才能干正事。 这样我们就可以保证先求和,再相减,然后再让主线程运行结束这个顺序。
使用 dispatch_apply 进行并发迭代:
对于上面的求和操作,我们也可以使用 dispatch_apply 来简化代码的编写.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
initData();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
__block int sum = 0;
__block int *pArray = data;
// iterations
//
dispatch_apply(Length, queue, ^(size_t i) {
sum += pArray;
});
NSLog(@" >> sum: %d", sum);
dispatch_release(queue);
[pool drain];
dispatch group
我们可以将完成一组相关任务的 block 添加到一个 dispatch group 中去,这样可以在 group 中所有 block 任务都完成之后,再做其他事情。比如 6 中的示例也可以使用 dispatch group 实现:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
initData();
__block int sum = 0;
// Create a semaphore with 0 resource
//
__block dispatch_semaphore_t taskSem = dispatch_semaphore_create(0);
// create dispatch semaphore
//
dispatch_queue_t queue = dispatch_queue_create("StudyBlocks", NULL);
dispatch_group_t group = dispatch_group_create();
dispatch_block_t task1 = ^(void) {
int s = 0;
for (int i = 0; i < Length; i++)
s += data;
sum = s;
NSLog(@" >> after add: %d", sum);
dispatch_semaphore_signal(taskSem);
};
dispatch_block_t task2 = ^(void) {
dispatch_semaphore_wait(taskSem, DISPATCH_TIME_FOREVER);
int s = sum;
for (int i = 0; i < Length; i++)
s -= data;
sum = s;
NSLog(@" >> after subtract: %d", sum);
};
// Fork
dispatch_group_async(group, queue, task1);
dispatch_group_async(group, queue, task2);
// Join
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(taskSem);
dispatch_release(queue);
dispatch_release(group);
[pool drain];
在上面的代码中,我们使用 dispatch_group_create 创建一个 dispatch_group_t,然后使用语句:dispatch_group_async(group, queue, task1)将 block 任务加入队列中,并与组关联,这样我们就可以使用 dispatch_group_wait(group, DISPATCH_TIME_FOREVER)来等待组中所有的 block 任务完成再继续执行。
至此我们了解了 dispatch queue 以及 block 并行编程相关基本知识,开始在项目中运用它们吧。
转:http://liwpk.blog.163.com/blog/static/363261702012413103111749/
Blocks与Dispatch Queue的使用的更多相关文章
- 装个蒜。学习下dispatch queue
dispatch queue的真髓:能串行,能并行,能同步,能异步以及共享同一个线程池. 接口: GCD是基于C语言的APT.虽然最新的系统版本中GCD对象已经转成了Objective-C对象,但AP ...
- GCD: 基本概念和Dispatch Queue 【转】
什么是GCD? Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写.从基本功能上讲,GCD有点像 NSOperationQueue,他们都允 ...
- GCD之dispatch queue深入浅出
GCD之dispatch queue深入浅出 http://blog.csdn.net/samuelltk/article/details/9452203
- GCD介绍(一): 基本概念和Dispatch Queue
什么是GCD? Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写.从基本功能上讲,GCD有点像NSOperationQueue,他们都允许 ...
- NSThread 、NSRunLoop 和 Dispatch Queue
iOS多线程编程中,NSOperation和NSOperationQueue无疑是最常用的,它们能满足绝大部分情况下的线程操作.但在完成一些特殊的任务时,我们还是要使用的NSThread和NSRun ...
- GCD系列 之(一):基本概念和Dispatch Queue
参考学习https://www.dreamingwish.com/article/grand-central-dispatch-basic-1.html系列文章,貌似也是翻译自他处的.觉得非常完整,就 ...
- IOS开发 GCD介绍: 基本概念和Dispatch Queue
iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 ØN ...
- GCD 学习(三)Main&Global Dispatch Queue
摘录自:http://zhuyanfeng.com/archives/3066 Main Dispatch Queue是在主线程中执行任务的Dispatch Queue.因为主线程只有1个,所以Mai ...
- GCD 学习(二)dispatch_queue_create创建Dispatch Queue
摘录于: http://zhuyanfeng.com/archives/3042 dispatch_queue_create 用于创建用户线程队列.可以创建Serial/Concurrent Disp ...
随机推荐
- 20165203《Java程序设计》第四周学习总结
教材学习内容总结 第5章 子类与继承 子类的继承性 子类和父类在同一包中的继承性:子类继承父类中不是private的成员变量和方法作为自己的成员变量和方法 子类和父类不在同一包中的继承性:子类只继承父 ...
- MFC+WinPcap编写一个嗅探器之六(分析模块)
这一节是程序的核心,也是最复杂的地方 首先需要明白的一点是,一般对于一个有界面的程序来说,往往需要多线程.本程序中除了界面线程外,抓包需要另外创建一个新的线程.在写抓包函数之前,首先要将前面两个模块的 ...
- Asp.Net MVC Razor视图引擎与My97DatePicker插件的结合
using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System. ...
- mysql 拾遗提高(函数、事务、索引)
目录 1.tips 2.事务(transaction) 3.索引(index) 4.数据库的导出和备份 5.函数 6.防SQL注入 7.使用Explain分析SQL语句 8.视图(view) 1.ti ...
- PHP的单引号和双引号
单引号内部的变量不会执行,双引号会执行. <?php $name = 'hello php'; echo "<h1>$name</h1>"; echo ...
- mysql正则表达式,实现多个字段匹配多个like模糊查询
现在有这么一个需求 一个questions表,字段有题目(TestSubject),选项(AnswerA,AnswerB,AnswerC,AnswerD,AnswerE) 要求字段不包含png,jpg ...
- Python 递归删除非空目录(包括子目录以及文件)
Python的OS模块自带rmdir和removedirs函数用于删除目录,但是两者都不能删除非空目录,以下代码定义了一个函数 remove_dir 用于删除非空目录. #作者官网 http://ww ...
- alpha冲刺阶段博客集合
作业格式 课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(团队) 团队名称: 那周余嘉熊掌将得队 作业目标:作业集合 团队信息: 队员学号 队员姓名 博客地址 备注 2216 ...
- 概率论与数理统计基础<1>:随机事件与随机变量
Part1. 随机事件 1-1.随机试验 随机试验:可以在相同条件下重复进行,每次试验的结果不止一个,事先知道所有可能的结果但不确定是哪一个的试验. 举例:重复的抛出一枚均匀的硬币就是一个随机试验,事 ...
- luoguP5024 保卫王国 动态dp
题目大意: emmmmm 题解: QAQ #include <cstdio> #include <cstring> #include <iostream> usin ...