前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程(二):GCD

多线程(二):GCD

作者头像
Helloted
发布2022-06-07 13:27:53
4200
发布2022-06-07 13:27:53
举报
文章被收录于专栏:Helloted
1、添加任务到队列(同步、异步):
dispatch_sync:

同步添加,将指定的任务block同步追加到queue中,在追加的block结束之前,dispatch_sync会一直等待;

如果在主线程上执行同步任务(任务也在主线程执行),会造成死锁:

代码语言:javascript
复制
//会造成死锁
dispatch_sync(dispatch_get_main_queue(), ^{
	//
});

但是在异步任务里可以用来切换到主线程

代码语言:javascript
复制
dispatch_async(dispatch_get_global_queue(0,0), ^{
	//耗时操作;
	dispatch_sync(dispatch_get_main_queue(), ^{
		//回到主线程;
	});
});

可以用来阻塞线程:

代码语言:javascript
复制
dispatch_sync(dispatch_get_global_queue(0,0), ^{
  sleep(2);
  NSLog(@"2秒后执行,但是会阻塞线程");
});
代码语言:javascript
复制
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
   NSLog(@"2秒后执行,但是不阻塞线程");
});
dispatch_async:

异步添加,将指定的Block”非同步”地追加到指定的Queue中,该线程不做等待,继续往下执行;

2、队列

Dispatch Queue:执行处理任务的队列,通过dispatch_async等函数API,在Block语法中记述想要执行的处理任务并将其追加到Dispatch Queue中,Dispatch Queue按照追加的顺序(先进先出FIFO)执行处理。

Serial Dispatch Queue(串行队列):

等待现在执行中处理结束,一旦生成Serial Dispatch Queue并追加处理。系统对于一个Serial Dispatch Queue就只生成并使用一个线程,但是如果生成过多的线程,会导致消耗大量的内存,引起大量的上下文切换,大幅度降低系统的响应性能,因此只在为了避免多个线程更新相同的资源导致数据竞争时使用。

Concurrent Dispatch Queue(并行队列):

不等待现在执行中处理结束,可以并行执行多个处理,并行处理的处理数量取决于当前系统状态,生成所需的线程执行处理,当处理结束,应当执行的处理数减少时,XNU内核会结束不再需要的线程,因此当想并行执行不发生数据竞争等问题处理时使用并行队列,有效管理线程,不会出现太多线程。

系统默认有一个串行队列:主队列(main_queue)和并行队列:全局队列(global_queue),不需要自己手动释放,或者自己创建用户队列(需要手动释放)。

主队列(main):

dispatch_queue_t mainQ = dispatch_get_main_queue() 注意:不能sync向主队列提交任务,因为会造成死锁,只能async提交任务

全局队列(global_queue):并发队列

有执行优先级

代码语言:javascript
复制
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

DISPATCH_QUEUE_PRIORITY_HIGH:             //优先级最高,在default,和low之前执行
DISPATCH_QUEUE_PRIORITY_DEFAULT           //默认优先级,在low之前,在high之后
DISPATCH_QUEUE_PRIORITY_LOW               //在high和default后执行
DISPATCH_QUEUE_PRIORITY_BACKGROUND        //提交到这个队列的任务会在high优先级的任务和已经提交到background队列的执行完后执行。
获取队列:(create_queue):

如果是串行队列:dispatch_queue_create(“createName”, DISPATCH_QUEUE_SERIAL)

如果是并行队列:推荐使用dispatch_get_global_queue

如果需要用到barrier和group,才来dispatch_queue_create(“createName”,DISPATCH_QUEUE_CONCURRENT)

尽管是ARC,使用结束后也要dispatch_release释放

代码语言:javascript
复制
dispatch_queue_t  concurrentQ = dispatch_queue_create("createName",DISPATCH_QUEUE_CONCURRENT)
dispatch_queue_t  serialQ = dispatch_queue_create("createName", DISPATCH_QUEUE_SERIAL)
改变队列优先级
dispatch_set_target_queue(restQueue, targetQueue);
暂停恢复队列
代码语言:javascript
复制
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_suspend(queue); //暂停队列queue
dispatch_resume(queue);  //恢复队列queue
3、延迟添加执行dispatch_after

并不是在多少秒后执行,而是在3秒后将任务添加到Dispatch Queue中

代码语言:javascript
复制
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
	//秒
});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,150ull *NSEC_PER_MSEC),dispatch_get_main_queue(), ^{
    //毫秒
});
4、dispatch_group与dispatch_barrier

dispatch_group应用于线程依赖:当添加到Queue中的所有任务都完成了,再来执行某个任务。

举例,异步下载两张图片,这在这两张图片下载完毕之后,将两张图片合成

代码语言:javascript
复制
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("com.gcd-group.www", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
    #异步下载第一张图片
 });
 
dispatch_group_async(group, queue, ^{
    #异步下载第二张图片
});
     
dispatch_group_notify(group, queue, ^{
    #两张图片下载完后进行合成
});

dispatch_barrier:barrier以为栅栏,阻碍。在串行队列中,无区别,但是在并行队列中,用这个函数添加的任务可以保证阻碍线程执行,即这个任务是串行执行的。可用于解决数据竞争问题。有个坑要注意,并行队列必必须是自己dispatch_queue_create创建的,不能用dispatch_get_global_queue

实现原理:queue中的其他block已经开始在各自分配的线程执行,当从queue检出一个barrier时,是等待其他的block都执行完毕再执行barrier,此时不会并发执行其他的block,直到该barrier执行完毕。 这相当于给当前已经运行的bock们加了一个group和notify,在notify里面执行了barrier,然后再执行barrier下面的block

举例。多个操作对数据库进行读写,读的操作可以异步进行,但是为了保证写的线程安全,则必须用dispatch_barrier

代码语言:javascript
复制
dispatch_async(queue, ^{NSLog(@"read");});
dispatch_async(queue, ^{NSLog(@"read");});
dispatch_async(queue, ^{NSLog(@"read");});

#可以保证写的时候只有这一个操作
dispatch_barrier_sync(queue, ^{NSLog(@"writing");});

dispatch_async(queue, ^{NSLog(@"read");});
dispatch_async(queue, ^{NSLog(@"read");});
5、dispatch_semaphore

semaphore是信号的意思,dispatch_semaphore有三个函数,分别是dispatch_semaphore_create,dispatch_semaphore_signal,dispatch_semaphore_wait

dispatch_semaphore信号量控制

6、dispatch_apply

重复执行某段代码

在某些场景下使用dispatch_apply会对性能有很大的提升,比如你的代码需要以每个像素为基准来处理计算image图片。同时dispatch apply能够避免一些线程爆炸的情况发生

代码语言:javascript
复制
//危险,可能导致线程爆炸以及死锁
for (int i = 0; i < 999; i++){
   dispatch_async(q, ^{...});
}
dispatch_barrier_sync(q, ^{});
// 较优选择, GCD 会管理并发
dispatch_apply(999, q, ^(size_t i){...});
7、dispatch_block_cancel

iOS8之后,提交到gcd队列中的dispatch block也可取消了,只需要简单的调用dispatch_block_cancel传入想要取消的block即可:

代码语言:javascript
复制
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_block_t block1 = dispatch_block_create(0, ^{
    NSLog(@"block1 begin");
    [NSThread sleepForTimeInterval:1];
    NSLog(@"block1 done");
});
dispatch_block_t block2 = dispatch_block_create(0, ^{
    NSLog(@"block2 ");
});
dispatch_async(queue, block1);
dispatch_async(queue, block2);
dispatch_block_cancel(block2);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、添加任务到队列(同步、异步):
  • dispatch_sync:
  • dispatch_async:
  • 2、队列
  • Serial Dispatch Queue(串行队列):
  • Concurrent Dispatch Queue(并行队列):
  • 主队列(main):
  • 全局队列(global_queue):并发队列
  • 获取队列:(create_queue):
  • 暂停恢复队列
  • 3、延迟添加执行dispatch_after
  • 4、dispatch_group与dispatch_barrier
  • 5、dispatch_semaphore
  • 6、dispatch_apply
  • 7、dispatch_block_cancel
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档