多线程-串行、并行行列,同步、异步使命
1、创立串行行列和并行行列
//并行行列
dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_CONCURRENT);
//串行行列
dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_SERIAL);
- 每次只有一个使命被履行。让使命一个接着一个地履行。(只敞开一个线程,一个使命履行结束后,再履行下一个使命)
- 能够让多个使命并发(一起)履行。(能够敞开多个线程,而且一起履行使命),并发行列的并发功能只有在异步(dispatch_async)办法下才有效。
2、同步异步使命
//同步
dispatch_sync(queue, ^{
NSLog(@"1");
});
//异步
dispatch_async(queue, ^{
NSLog(@"1");
});
同步履行:
- 同步添加使命到指定的行列中,在添加的使命履行结束之前,会一直等候,直到行列里边的使命完结之后再持续履行。
- 只能在当时线程中履行使命,不具备敞开新线程的才能。
异步履行:
- 异步添加使命到指定的行列中,它不会做任何等候,能够持续履行使命。
- 能够在新的线程中履行使命,具备敞开新线程的才能。
异步履行(async) 尽管具有敞开新线程的才能,但是并不一定敞开新线程。这跟使命所指定的行列类型有关。
默认大局并发行列:dispatch_get_global_queue
第一个参数表示行列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT
。
第二个参数暂时没用,用0
即可。
区别 | 并发行列 | 串行行列 | 主行列 |
---|---|---|---|
同步(sync) | 没有敞开新线程,串行履行使命 | 没有敞开新线程串行履行使命 | 死锁卡住不履行 |
异步(async) | 有敞开新线程,并发履行使命 | 有敞开新线程(1条)串行履行使命 | 没有敞开新线程串行履行使命 |
信号量 dispatch_semaphore_t
GCD
中的信号量dispatch_semaphore_t
中首要有三个函数:
-
dispatch_semaphore_create
:创立信号 -
dispatch_semaphore_wait
:等候信号 -
dispatch_semaphore_signal
:开释信号
1、dispatch_semaphore_create
参数为int,表示信号量初始值,需大于等于0,不然创立失利,回来一个dispatch_semaphore_t
2、dispatch_semaphore_wait
参数1:
需传递一个 dispatch_semaphore_t 类型目标,对信号进行减1,然后判别信号量巨细
参数2:
传递一个超时时刻:dispatch_time_t 目标
- 减1后信号量小于0,则堵塞当时线程,直到超时时刻到达或者信号量大于等于0后持续履行后边代码
- 减1后信号量大于等于0,对dispatch_semaphore_t 进行赋值,并回来dispatch_semaphore_t目标,持续履行后边代码
3、dispatch_semaphore_signal
参数:dispatch_semaphore_t
进行信号量加1操作,假如加1后成果大于等于0,则持续履行,不然持续等候。
用法:
- (void)startAsync{
//创立信号量 值为0
self.sem = dispatch_semaphore_create(0);
//敞开异步并发线程履行
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"dispatch_semaphore 2\n");
sleep(5);
//发送信号,信号量值+1
dispatch_semaphore_signal(self.sem);
NSLog(@"dispatch_semaphore 3\n");
});
NSLog(@"dispatch_semaphore 0\n");
//信号量 值-1 小于0 等候信号。。。
dispatch_semaphore_wait(self.sem, DISPATCH_TIME_FOREVER);
NSLog(@"dispatch_semaphore 1\n");
}
履行次序0 2 1 3 1和3不确定次序
假如初始化创立是信号量值为1
履行次序0 1 2 3
常用总结:
1、异步并发线程次序履行
2、异步并发线程控制最大并发数,比方下载功能控制最大下载数
调度组 dispatch_group_t
首要API:
-
dispatch_group_create
:创立组 -
dispatch_group_async
:进组使命 -
dispatch_group_notify
:组使命履行结束的通知 -
dispatch_group_enter
:进组 -
dispatch_group_leave
:出组 -
dispatch_group_wait
:等候组使命时刻
组合用法1:
- (void)dispatchGroupAsync{
//创立调度组
dispatch_group_t group = dispatch_group_create();
//获取大局并发行列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//敞开异步线程
dispatch_group_async(group, queue, ^{
sleep(2);
NSLog(@"11");
});
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"12");
});
dispatch_group_async(group, queue, ^{
sleep(3);
NSLog(@"13");
});
NSLog(@"14");
dispatch_group_notify(group, queue, ^{
//收到履行完结的通知后履行
NSLog(@"15");
});
//等候调度组履行完结
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
调度组履行完结后履行
NSLog(@"16");
}
用法2:
- (void)dispatchSyncEnterGroup{
//创立调度组
dispatch_group_t group = dispatch_group_create();
//获取大局并发行列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//进入调度组
dispatch_group_enter(group);
//履行异步使命
dispatch_async(queue, ^{
sleep(2);
NSLog(@"21");
//履行完结后立刻调度组
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"22");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(3);
NSLog(@"23");
dispatch_group_leave(group);
});
NSLog(@"24");
dispatch_group_notify(group, queue, ^{
//履行完后回调
NSLog(@"25");
});
NSLog(@"26");
//等候调度组履行完结
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"27");
}
总结:
1、dispatch_group_async 是对dispatch_group_enter和dispatch_group_leave的封装
2、dispatch_group_enter和dispatch_group_leave的须成双成对的呈现
事情源 dispatch_source_t
首要API:
-
dispatch_source_create
:创立源 -
dispatch_source_set_event_handler
: 设置源的回调 -
dispatch_source_merge_data
: 源事情设置数据 -
dispatch_source_get_data
: 获取源事情的数据 -
dispatch_resume
:康复持续 -
dispatch_suspend
:挂起 -
uintptr_t dispatch_source_get_handle(dispatch_source_tsource)
//得到dispatch源创立,即调用dispatch_source_create的第二个参数 -
unsignedlongdispatch_source_get_mask(dispatch_source_tsource)
; //得到dispatch源创立,即调用dispatch_source_create的第三个参数
源的类型dispatch_source_type_t
:
-
-
DISPATCH_SOURCE_TYPE_DATA_ADD
:用于ADD
兼并数据
-
-
-
DISPATCH_SOURCE_TYPE_DATA_OR
:用于按位或
兼并数据
-
-
-
DISPATCH_SOURCE_TYPE_DATA_REPLACE
:跟踪
通过调用dispatch_source_merge_data
取得的数据的分配源,新取得的数据值将替换
没有交付给源处理程序 的现有数据值
-
-
-
DISPATCH_SOURCE_TYPE_MACH_SEND
:用于监督Mach端口
的无效称号
通知的调度源,只能发送没有接收权限
-
-
-
DISPATCH_SOURCE_TYPE_MACH_RECV
:用于监督Mach端口
的挂起
音讯
-
-
-
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
:用于监控
系统内存压力变化
-
-
-
DISPATCH_SOURCE_TYPE_PROC
:用于监督外部进程
的事情
-
-
-
DISPATCH_SOURCE_TYPE_READ
:监督
文件描述符以获取可读取的挂起字节
的分配源
-
-
-
DISPATCH_SOURCE_TYPE_SIGNAL
:监控当时进程
以获取信号的调度源
-
-
-
DISPATCH_SOURCE_TYPE_TIMER
:基于计时器提交事情
处理程序块的分配源
-
-
-
DISPATCH_SOURCE_TYPE_VNODE
:用于监督
文件描述符中定义的事情
的分配源
-
-
-
DISPATCH_SOURCE_TYPE_WRITE
:监督
文件描述符以获取可写入字节
的可用缓冲区空间的分配源。
-
1、dispatch_source_create 参数:
-
dispatch_source_type_t
要创立的源类型 -
uintptr_t
句柄 用于和其他事情并定,很少用,一般为0 -
uintptr_t
mask 很少用,一般为0 -
dispatch_queue_t
事情处理的调度行列
用法:
self.sourceAdd = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_global_queue(0, 0));
2、dispatch_source_set_event_handler 设置回调函数,当触发源事情时履行
//需求留意循环引证
dispatch_source_set_event_handler(self.sourceAdd, ^{
需求履行的代码
});
//启动
dispatch_resume(self.sourceAdd);
//挂起,即暂停
dispatch_suspend(self.sourceAdd);
这两个API需求成对运用,不行屡次挂起或者屡次康复
3、dispatch_source_cancel 取消事情源,取消后不行再康复或挂起,需求再次创立
4、dispatch_source_set_timer 当事情源类型为定时器类型(DISPATCH_SOURCE_TYPE_TIMER)时,设置开端时刻、重复时刻、允许时刻误差
定时器实现比较简略容易,网上教程也多,这儿首要介绍一下:DISPATCH_SOURCE_TYPE_DATA_ADD、DISPATCH_SOURCE_TYPE_DATA_OR、DISPATCH_SOURCE_TYPE_DATA_REPLACE。
先说下成果:
- DISPATCH_SOURCE_TYPE_DATA_ADD 会把事情源累加 能够记录总共发送多少次事情进行兼并
- DISPATCH_SOURCE_TYPE_DATA_OR 会把事情源兼并,终究得到的数据源数为1
- DISPATCH_SOURCE_TYPE_DATA_REPLACE 会用最新事情源替换旧有未处理事情,终究得到的数据源数为1
- 循环10000次实践跑处理回调事情次数 add315 or275 replace 284
从成果上来看,当需求把快速频频的重复事情进行兼并,最好的选择是DISPATCH_SOURCE_TYPE_DATA_OR
,运用场景,监听音讯时,多音讯频频下发需求改写UI,假如不进行兼并处理,会导致UI太过频频的改写,影响终究作用,且对性能开销过大。
当然,相似的场景也可运用其他办法处理,比方建立音讯池,接收音讯后标记音讯池状态及变化,然后定时从音讯池中取音讯。诸如此类的办法较多,假如只是简略的处理,上面的DISPATCH_SOURCE_TYPE_DATA_OR形式应该满意运用。
代码:
//创立源
self.sourceAdd = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_global_queue(0, 0));
//弱引证
__weak typeof(self) weakifySelf = self;
//设置回调事情
dispatch_source_set_event_handler(self.sourceAdd, ^{
//强引证
__strong typeof(self) strongSelf = weakifySelf;
//获取接收到的源数据
strongSelf.handleData = dispatch_source_get_data(strongSelf.sourceAdd);
NSLog(@"dispatch_source1 %ld\n",strongSelf.handleData);
//需求履行的代码
[strongSelf sourceHandle];
});
//敞开源
dispatch_resume(self.sourceAdd);
for (int i = 0; i<10000; i ++) {
[self dispatchSource];
}
- (void)dispatchSource{
NSLog(@"dispatch_source2 %ld\n",self.handleData);
//发送源信号
dispatch_source_merge_data(self.sourceAdd, 1);
}