1,今天更新一下关于线程的一些小知识。
前提:dispatch_get_main_queue()本质是串行队列,dispatch_get_global_queue(0, 0)本质是并行队列
串行队列:DISPATCH_QUEUE_SERIAL 最多开辟一个线程
并行队列:DISPATCH_QUEUE_CONCURRENT 可开启n的线程,n>=0
主队列执行async任务时,会在主线程执行,因为主线程就是主队列开辟的线程。
并行队列执行sync任务时,不会开辟新线程,会在当前线程中执行。
一、设置线程并发量
线程并发量:如果需要加载1000张图片,如果开启1000个子线程,那么CPU可能就忙不过来了,这时我们可以设置最大并发量来更加合理的利用资源。同时只允许10个线程下载,每个任务完成后,让改线程执行下一个任务
两种实现:
1、GCD:通过dispatch_semaphore实现
static dispatch_semaphore_t semaphoreLock;
void testDispatch_semaphore () {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
semaphoreLock = dispatch_semaphore_create(5);
});
dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER);
//code...
dispatch_semaphore_signal(semaphoreLock);
}
其中dispatch_semaphore_create(5)中的5就是最大并发数。执行到wait时,会变成4,只到变成0,在有线程来到wait就会阻塞到这里了,要等要某个线程dispatch_semaphore_signal()时,信号就会+1,然后等待的线程就是执行,始终保持着最大线程数是5
2、NSOperationQueue实现
NSOperationQueue有个属性maxConcurrentOperationCount设置最大并发数,和dispatch_semaphore_create一样
NSOperationQueue *queue =[[NSOperationQueue alloc] init];
[queue addOperation:...];
[queue addOperation:...];
queue.maxConcurrentOperationCount = 5;
注意:线程的cancel操作都不能取消正在执行的任务,只能取消在队列中排队的任务。要想取消正在执行的任务,只能通过添加信号量的方式,强制让任务提前return
//线程已经停止,需要跳出循环
if ([_invo isCancelled]) {
return; // 跳出循环。
}
//或者
if (_stopFlag){
return;
}
二、GCD常用函数
1、dispatch_barrier_async
dispatch_barrier_async:栅栏化,在栅栏任务前面的任务可以异步执行,等到前面的异步任务执行完了,才会执行栅栏中的任务,栅栏后面的任务也可以异步执行。
dispatch_barrier_async要搭配并发队列才能达到隔离效果,如果使用的是串行队列,那么就会一个线程一个线程执行,没有隔离效果
void testGCD () {
dispatch_queue_t queue = dispatch_queue_create("ob", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(2);
NSLog(@"end -- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(2);
NSLog(@"end -- %@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(4);
NSLog(@"end -- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(2);
NSLog(@"end -- %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(2);
NSLog(@"end -- %@",[NSThread currentThread]);
});
}
打印如下:
2020-07-09 14:01:27.801176+0800 start -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
2020-07-09 14:01:27.801179+0800 start -- <NSThread: 0x10063a510>{number = 2, name = (null)}
2020-07-09 14:01:29.806139+0800 end -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
2020-07-09 14:01:29.806139+0800 end -- <NSThread: 0x10063a510>{number = 2, name = (null)}
2020-07-09 14:01:29.806349+0800 start -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
2020-07-09 14:01:33.811750+0800 end -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
2020-07-09 14:01:33.811914+0800 start -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
2020-07-09 14:01:33.811915+0800 start -- <NSThread: 0x10063a510>{number = 2, name = (null)}
2020-07-09 14:01:35.816482+0800 end -- <NSThread: 0x10063a510>{number = 2, name = (null)}
2020-07-09 14:01:35.816497+0800 end -- <NSThread: 0x1005156d0>{number = 3, name = (null)}
二、dispatch_group
- dispatch_group_enter :通知 group,下个任务要放入 group 中执行了
- dispatch_group_leave: 通知 group,任务成功完成,要移除,与 enter成对出现
- dispatch_group_wait: 在任务组完成时调用,或者任务组超时是调用(完成指的是enter和leave次数一样多)
- dispatch_group_notify: 只要任务全部完成了,就会在最后调用
其中,dispatch_group_notify安全起见要使用dispatch_group_wait,等到前面的执行完了才行,同样的只能适应在并行队列。串行队列按顺序执行,并且一个线程执行所有任务。即使使用async也不会创建多线程。
void testGroup () {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("ob", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_notify(group, queue, ^{
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"notify -- %@",[NSThread currentThread]);
});
// dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(5);
NSLog(@"end -- %@",[NSThread currentThread]);
// dispatch_group_leave(group);
});
dispatch_group_async(group, queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(1);
NSLog(@"end -- %@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"start -- %@",[NSThread currentThread]);
sleep(3);
NSLog(@"end -- %@",[NSThread currentThread]);
});
}
后期更新中。。。