GCD解毒

没错就是解毒

前言


GCD做为iOS开发中多线程管理的重要帮手。起初我只能说是用过,但是并没有较为仔细的了解它。最近又一次重新梳理了一下,虽然目前来看,还存在一些问题,无法解释。但还是先做个笔记,与大家分享下。同时,希望大家也能一起探索或者帮忙解答下这些问题:]

<p>

一些概念


首先,我们来解读一些基本的概念。在多线程开发中我们经常会遇到很多的名词,一时间也没办法分清他们到底是什么意思。所以我在这里做个简单的整理

并行 和 并发

并发: 统一执行很多任务,表面上同时发生,但是实际上是计算机分时处理的结果,即CPU在不同的任务之间进行切换,执行一段时间后切换到另一个线程。
并行:真正意义上的同时执行任务。

两者的区别实际上用一张图就能很好的说明

Paste_Image.png

同步 和 异步

同步:等操作完成才返回
异步:直接返回

串行队列 和 并发队列

串行队列:一次只执行一个任务

Paste_Image.png

并发队列: 一次执行多个任务
Paste_Image.png

这里我们需要说明的是,无论是并发队列还是并行队列,他们都是FIFO的,也就是说先添加到队列中的任务会先被执行,但是对于并发队列而言,我们不能保证执行完成时的顺序。另外,在一些博文中会将Concurrent Queue翻译为 并行队列,个人认为并不是很严谨。首先是因为Concurrent 本意就是并发,并且如果使用并发这个名词,对于一些初学者来讲可能会产生误导,队列中的任务到底是并发执行还是并行执行的呢?

进程 和 线程

进程:是操作系统对于正在运行的程序的一种抽象,在系统上可以同时运行多个进程,而每个进程都好像在独立使用硬件
线程:一个进程实际上可以由多个线程的执行单元组成,每个线程都在进程的上下文中,共享同样的代码和全局数据
进程、线程和应用程序的关系:进程为应用程序开辟内存空间,而线程执行应用程序代码
进程和线程的关系:进程由线程组成、一个进程理论上可以有很多的线程,但至少有一个主线程。

死锁

死锁: 两个或多个线程相互等待而导致任何一个线程都不能执行。

概念汇总

图片发自简书App

关于一些问题的想法


我们经常会看到以下代码

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //[self do something];
    });

这段代码表示我们“开启一个异步线程,在全局队列中执行”

那么我们如果我们将dispatch_get_global_queue()函数改为dispatch_get_main_queue()就会说我们在主线程上做处理事务,而事实上我们使用这个函数创建或得到的是一个队列而非线程。

更准确的说,我认为,我们使用GCD的时候应该是面向队列,而不是线程。在很多的博客中都会使用NSLog(@"current thread is %@", [NSThread currentThread])这段代码来打印当前的线程,然后告诉你说我们在XX线程上执行了代码。的确,这样的方式更加直接的说明了问题。但是就像我之前提到的,开发者应该面向的是队列而不是线程,所以这只是辅助说明的一种方式。

OK,接下来我们讨论下dispatch_async和dispatch_sync函数都干了些什么。开始我以为他们是创建线程用的,就如一些的博文中会讲到,“每执行一次任务的时候,dispatch_async总会为我们开辟一个新的线程”

真的是这样吗?

我在文档里看到如下说明

dispatch_sync

Submits a block object for execution on a dispatch queue and waits until that block completes.
Submits a block to a dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock

dispatch_async

Submits a block for asynchronous execution on a dispatch queue and returns immediately.
This function is the fundamental mechanism for submitting blocks to a dispatch queue. Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue. Independent serial queues are processed concurrently with respect to each other.

这里我认为,这两个函数只是用于提交任务或者说block的。他们唯一的区别是会不会等待任务完成。对于dispatch_sync而言,他会提交任务,同时阻塞当前的线程直到任务执行完成才会返回。 dispatch_async则会在提交任务之后直接返回,不阻塞和等待。如此一来,真正和与线程相关的就可能是队列了。

另一种视角


前面提到的在GCD中我们只是面向队列和任务。队列包括串行队列和并发队列,而任务提交是同步或者异步的。那么我们就来看下这些概念排列组合后的场景。

同步提交 + 串行队列

Paste_Image.png

说明:在调用dispatch_sync方法的时候我们指定了添加任务的队列和任务(block)。那么该方法就会提交该任务到串行队列中,然后然后阻塞线程,等待任务完成之后再返回。对于串行队列,前面的概念解释里已经说过了,任务一个接一个执行。

异步提交 + 并发队列

Paste_Image.png

说明:异步提交的时候,dispatch_async函数提交然后直接返回。区别是并发队列会一次执行多个任务。

同步提交 + 并发队列

Paste_Image.png

异步提交 + 串行队列

Paste_Image.png

代码部分

我们在从代码部分去理解同步和异步的问题


图片发自简书App

左侧两段输出,我们可以看到,都是同步提交,无论是提交到串行队列还是并发队列,执行的顺序都是一样的。并且提交任务前后的代码的顺序都是依次执行的。

在看右侧部分,由于异步提交后直接返回不等待执行完成。所以任务提交前后的代码会先于任务中的代码执行。

接下来,我们在从代码的角度去理解串行队列和并发队列

并发

图片发自简书App

在同样是异步的前提下,任务前后的代码都先于任务执行了(当然这并不是绝对的)。我们看到在串行队列中,执行任务的线程不在主线程中,但是他们都是在一个线程中去处理。也正因为任务前后的代码执行和任务代码执行的线程不同,所以我们并不能保证任务部分的代码和任务后的代码的执行先后性。因此会出现任务代码先执行,在执行过程又出现任务后的打印输出。

图片发自简书App

同样是同步提交的情况下,两个输出完全一致。串行队列同步提交的情况我们可以理解,因为它一次只执行一个任务,所以线程号是一样的。但是,并发队列的情况下,该怎么理解?其实也很简单,因为他是同步提交,需要等到当前任务完成后返回再进行后续的操作,所以即使是并发的队列,我们看到的效果还是和串行一样。

遗留的问题

首先很感谢你能看到这里,听我瞎扯那么多。
以上是我个人的理解,感觉与一些博文中的思想有些出入,所有我也不是很确定。我仅以
我看到的为参考,并提出自己的理解。

目前还有以下问题暂时没有想通:

1)队列和线程的关系

从文档中有看到系统实际上有维持一个线程池,但是没有说清队列和它有什么具体的关系。

2)队列和主线程的关系

如下图,同样是在主线程中执行,但是如果将这个queue改成main queue时就会报错。

图片发自简书App

归根结底还是没有理清线程和队列的关系,或者说是主线,队列,其它线程这三者的关系。

如果觉得我的想法有问题的同学,请帮忙指正,万分感谢。
如果觉得我理解有道理的同学,希望能一起探讨一下遗留的问题,共同完善知识体系:]

最后放上源代码
GCD解毒Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • GCD笔记 总结一下多线程部分,最强大的无疑是GCD,那么先从这一块部分讲起. Dispatch Queue的种类...
    jins_1990阅读 752评论 0 1
  • 从哪说起呢? 单纯讲多线程编程真的不知道从哪下嘴。。 不如我直接引用一个最简单的问题,以这个作为切入点好了 在ma...
    Mr_Baymax阅读 2,734评论 1 17
  • GCD GCD简介 Grand Central Dispatch中枢调度器 纯C语言的,提供了非常强大的函数 优势...
    彼岸的黑色曼陀罗阅读 428评论 0 0
  • iOS中GCD的使用小结 作者dullgrass 2015.11.20 09:41*字数 4996阅读 20199...
    DanDanC阅读 810评论 0 0
  • 一,奇迹 1,今天我很开心❤一切都很顺利!诸事顺顺当当的!谢谢我的天使真我指导灵给我完美生活! 2,今天我很开心❤...
    张秀琦阅读 219评论 0 0