相关书籍的一点笔记
1. 普通异步追加
dispatch_async(serialDispatchQueue1, ^{ });
在某个线程异步追加某个任务;
2.普通线程创建
dispatch_queue_tserialDispatchQueue1=dispatch_queue_create("线程1",NULL);
线程初始化,参数:1,线程名;2.线程类型:串行传Null 并行传:DISPATCH_QUEUE_CONCURRENT;
多个串行线程之间也是互相并行的。可能会出现多个线程使用一个数据的情况(数据竞争)建议串行线程,否则建议并行线程;
3.特殊线程
dispatch_queue_t main_queue=dispatch_get_main_queue();主线程(NSRunLoop)
更新UI的操作要回调主线程完成,主线程有且仅有一个;
dispatch_queue_t globalDispatchQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);始终存在的并行线程,每个程序都能获取,不需要创建,有四个优先级
4.设置线程优先级
dispatch_set_target_queue(serialDispatchQueue1, globalDispatchQueue);
将参数1的线程运行到参数2的线程上,获得参数二的优先级,如果参数二为串行线程,那被加到参数二上的线程互相串行执行。(参数1线程自身可以并行)
5.延时方法
dispatch_time_t time_t=dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);
dispatch_after(time_t, serialDispatchQueue1, ^{ });
在指定时间追加到某队列,这里是现在开始的1S后;
6.线程组和线程等待
dispatch_group_t group=dispatch_group_create();创建方法
dispatch_group_async(group, serialDispatchQueue1, ^{ });往里添加线程
dispatch_group_notify(group, dispatch_get_main_queue(), ^{ });线程组结束回调
线程组结束回调总是在线程组所有线程执行完之后调用;
BOOL groupDone=dispatch_group_wait(group, DISPATCH_TIME_FOREVER);线程执行情况查询
0是执行完毕,其他值未执行完毕;第二个参数是超时时间;
此函数调用时,调用函数的线程会中断等待返回结果或至超时,传DISPATCH_TIME_NOW可以立即返回结果,而传DISPATCH_TIME_FOREVER则一定等待对应线程结束后返回且返回结果恒为0;
7.栅栏方法
针对并行线程使用,串行线程本身就是没有栅栏需求的。
dispatch_barrier_async(serialDispatchQueue1, ^{ });追加到对应线程的栅栏方法
栅栏方法的功能://(线程同步,并行线程强制串行)
1)阻塞后续事件的追加,等待已追加事件的完成。
2)在已追加事件全部完成之后,执行自己的追加方法。
3)在自己的追加事件完成之后,取消阻塞。
8.同步追加
dispatch_sync(serialDispatchQueue1, ^{});同步追加方法
同步追加类似于线程等待方法,会阻塞执行线程直至追加任务返回,栅栏方法也有同步追加。
同步追加适用于需要立刻使用返回结果的场景,但要防止线程死锁。
线程死锁:当一个任务的逻辑执行顺序必须在自己之后,那么死锁。
比如串行线程执行向自己追加同步任务,会出现线程停下来等自己的情况,这种情况是不可能完成的,所以会死锁,解除死锁只要打破这个逻辑链就好了,采用异步追加或者不要在本线程完成或者追加到并行线程。(并行线程可以等待自己,因为并行线程等待的时候是可以正常执行任务的)
同步追加和异步追加指的是:要不要阻塞执行追加的线程等待结果回调;
串行队列和并行队列指的是:追加过去的任务在线程里要不要按次序执行;
9.批次追加
dispatch_apply(10, serialDispatchQueue1, ^(size_t index) {});
同步追加一个任务的N次到指定线程,block提供了当前执行bolck的索引,同时也是同步等待返回,建议用异步追加先追加到并行线程,然后执行完任务线程返回;
10.线程挂起/恢复
当一个线程追加大量处理时,可能到某个任务返回后,我要暂停任务等待外部事件结束后再继续处理,这个时候需要线程的挂起与恢复。
dispatch_suspend(serialDispatchQueue1);线程挂起
dispatch_resume(serialDispatchQueue1);线程恢复
挂起不影响已执行与正在执行的任务,但会停止执行尚未执行的任务。
11.信号量
信号量用来控制并行任务数量。
当我对同时执行的任务数量上限有要求时,可以使用信号量来实现,比如100000个任务同时访问同一个数组,如果同时异步执行,会因为数据竞争问题crash。此时用信号量控制并发,分三步:
1)设置最大信号数量为1。
dispatch_semaphore_t semaphore=dispatch_semaphore_create(1);//最大信号数量
2)在每次执行任务的时候宣布占用一个信号。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
3)在每次执行完任务的时候宣布解除占用信号。
dispatch_semaphore_signal(semaphore);
其中宣布占用方法在等待时间为 DISPATCH_TIME_FOREVER 时也是同步等待方法,这个时间可以是另一个超时时间,这取决于需求。
semaphore是一个0-最大信号数量 的值,取决于剩余信号量,当它大于0时,dispatch_semaphore_wait() 方法返回成功(0),并占用一个信号量使计数减一,当它等于0时,wait方法持续等待至超时。
dispatch_semaphore_signal() 方法在任务结束后调用,使信号量加一,所有任务完成,信号量回归最大信号数量。
12.单例
通过静态计数让代码只运行一次,炒鸡简单好用的API;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{});
自定义单例会存在多线程竞争问题,这个不会;
13. 数据分割读取(笔者懒癌发作当场去世,尚未演示效果)
大文件的分割并行处理
1)创建dispatch_io_t对象
dispatch_io_t dispatch_io_create( dispatch_io_type_t type, dispatch_fd_t fd, dispatch_queue_t queue, void (^cleanup_handler)(int error));
创建dispatch_io_t对象,参数依次为:
1》type 通道类型 DISPATCH_IO_STREAM 0 顺序访问文件,DISPATCH_IO_RANDOM 1
随机访问文件
2》fd,文件标识符
3》queue 错误回调线程
4》block 错误回调
2)读写操作
void dispatch_io_read( dispatch_io_t channel, off_t offset, size_t length, dispatch_queue_t queue, dispatch_io_handler_t io_handler);
1》channel 读写对象
2》offset 读写偏移量 DISPATCH_IO_RANDOM 类型的通道有效,指定要读写的文件位置偏移量,而DISPATCH_IO_STREAM忽略此参数,从当前位置读写。
3》length 分割数据的大小;
4》queue 分割数据每次读写完毕之后回调的线程;
5》block 对应回调函数;
网友评论