Dispatch Queue:
开发者将需要执行的任务添加到合适的Dispatch Queue中即可,Dispatch Queue会根据任务添加的顺序先到先执行,其中有以下几种队列:
1.main dispatch queue
功能跟主线程一样,通过dispatch_get_main_queue()来获取,提交到main queue的任务实际上都是在主线程执行的,所以这是一个串行队列
2.global dispatch queues
系统给每个应用提供四个全局的并发队列,这四个队列分别有不同的优先级:高、默认、低以及后台,用户不能去创建全局队列,只能根据优先级去获取:
dispatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3.user create queue
用户可以通过dispatch_queue_create自己创建队列,该函数有两个参数,第一个是队列的名称,在debug的时候方便区分;第二个是队列的一些属性,NULL或者DISPATCH_QUEUE_SERIAL创建出来的队列事串行队列,如果传递DISPATCH_QUEUE_CONCURRENT则为并行队列。
// 创建并行队列
dispatch_queue_t queue;
queue=dispatch_queue_create(“com.example.MyQueue”, DISPATCH_QUEUE_CONCURRENT);
4.队列优先级
dispatch_queue_create创建队列的优先级跟global dispatch queue的默认优先级一样,假如我们需要设置队列的优先级,可以通过dispatch_queue_attr_make_with_qos_class或者dispatch_set_target_queue方法;
Quality of Service 枚举来使用user interactive,user initiated,utility和bakground
通过这些告诉系统我们在进行什么样的工作,然后系统会通过合理的资源控制来最高效的执行任务代码,其中主要涉及到CPU调度的优先级、IO优先级、任务运行在哪个线程以及运行的顺序等等,我们通过一个抽象的Quality of Service 参数来表明任务的意图以及类别。
一个典型的例子就是数据的读写,通常为了防止文件读写导致冲突,我们会创建一个串行的队列,所有的文件操作都是通过这个队列来执行,比如FMDB,这样就可以避免读写冲突。不过其实这样是有提升空间的,当没有更新数据时,读操作其实是可以并行进行的,而写操作需要串行执行。
Dispatch IO
当我们要读取一份较大文件的时候,多个线程同时去读肯定比一个线程去读的速度要快,要实现这样的功能可以通过dispatch io跟dispatch data来实现,通过dispatch io读文件时,会使用global dispatch queue将一个文件按照一个指定的分块大小同时去读区数据,类似于:
dispatch_async(queue,^{/读取0-99字节/});
dispatch_async(queue,^{/读取100-199字节/});
dispatch_async(queue,^{/读取200-299字节/});
…………
将文件分成一块一块并行读取,读取的数据通过Dispatch Data进行结合和分割。
dispatch_io_create函数生成Dispatch I/O,并指定发生error时用来执行处理的block,以及执行该block的Dispatch Queue。
dispatch_io_set_low_water函数设置一次读取的大小
dispatch_io_read函数使用Global Dispatch Queue开始并发读取。每当各个分割的文件块读取结束时,会将含有文件块数据的Dispatch Data(这里指pipedata)传递给dispatch_io_read函数指定的读取结束时回调用的block,这个block拿到每一块读取好的Dispatch Data(这里指的是pipe data),然后进行合并处理。
想提高文件读取速度,可以尝试使用Dispatch I/O
Dispatch Source
Dispatch Source其实就是对kqueue功能的封装,可以去查看dispatch_source的C源码实现
kqueue是在XNU内核中发生各种事件时,在应用程序编程方执行处理的技术,其CPU负荷非常小,尽量不占用资源。
kqueue可以说是应用程序处理XNU内核中发生的各种事件的方法中最优秀的一种。
Dispatch Source可处理以下事件
DISPATCH_SOURCE_TYPE_DATA_ADD 变量增加
DISPATCH_SOURCE_TYPE_DATA_OR 变量OR
DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口发送
DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口接收
DISPATCH_SOURCE_TYPE_PROC 检测到与进程相关的事件
DISPATCH_SOURCE_TYPE_READ 可读取文件映像
DISPATCH_SOURCE_TYPE_SIGNAL 接收信号
DISPATCH_SOURCE_TYPE_TIMER 定时器
DISPATCH_SOURCE_TYPE_VNODE 文件系统有变更
DISPATCH_SOURCE_TYPE_WRITE 可写入文件映像
事件发生时,在指定的Dispatch Queue中可执行事件的处理。
__block size_t total = 0;
size_t size = 要读取的字节数
char buff = (char)malloc(size);
//设定为异步映像
fcntl(socked,F_SETFL,O_NONBLOCK);
//获取用于追加事件处理的Global Dispatch Queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT,0);
// 基于READ事件做成Dispatch Source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socked, 0, queue);
//指定发生READ事件时执行的处理
dispatch_source_set_event_handle(source, ^{
//获取可读取的字节数
size_t available = dispatch_source_get_data(source);
// 从映像中读取
int length = read(socked, buff, available);
// 发生错误时取消Dispatch Source
if ( length < 0){
// 错误处理
dispatch_source_cancel(source);
}
total += length;
if(total == size) {
// buff的处理
// 处理结束,取消Dispatch Source
dispatch_source_cancel(source);
}