高效使用libdispatch的技巧

libdispatch(or GCD)是最容易被使用错误的API之一,这是因为它的用法以及令人难懂的文档和API。如果你打算使用这个库,下面是总结是你要知道的。本文末尾有很多参考资料,包库对苹果自己的libdispatch维护人员(Pierre Habouzit)的评论的引用。

具体的结论如下:

  • 应该创建适量、常驻、明确职能的队列。这些队列供应用程序执行上下文及其它并行任务(UI线程、后台线程等)。需要注意的是,如果这些队列处于活动状态,意味着将有等量的线程数运行。在大部分的App中,只需要不超过3或者4个队列即可。
  • 优先使用串行队列,如果使用过程中发现性能瓶颈,可以先查找原因。即使并行能提供帮助,也需谨慎使用,并且始终在系统压力下验证。尽可能的重用队列,除非增加队列能带来明显的收益。
  • 你可以创建比较多非全局行的队列(重点是他们有不同的标识),如使用DispatchQueue(label:target:)方式创建的队列。
  • 不要使用DispatchQueue.global()的方式获取队列。全局队列容易导致线程爆炸:libdispatch将阻塞、睡眠、等待、锁定的线程视为非活动线程,从而在需要程序调度时又会创建新的线程。注意,我们不能保证线程永远不会被阻塞,事实是,即使我们仅仅使用系统库都可能会发生这种问题。全局队列对qospriorities的支持也不友好。苹果工程师,libdispatch的维护者宣称它是"它提供了最糟糕的dispatch API"。用自定义的队列代替它运行你的代码。
  • 并发队列相对串行队列不是最佳实践。除非衡量了确切的收益,否则直接使用并发队列更像是过早优化。
  • 对于派发的小于1ms的任务,使用queue.async()的方式是非常糟糕的。基于libdispatch的过渡分配行为,它极有可能会创建一个新的线程。宁愿使用锁定来保护共享状态(而不是切换执行上下文)。
  • 有些类/库设计为同步API,重用调用者的执行上下文(而不是创建私有队列,这可能导致糟糕的性能)这意味着得使用传统的锁来保证线程安全。
  • os_unfair_lock是目前系统中最快的锁(优先级更好,上下文切换更少),用于取代OSSpinLock(取代原因可参考《不再安全的 OSSpinLock》),尝试获取已加锁的线程无需忙等,解锁时由内核唤醒。和OSSpinLock一样,os_unfair_lock也没有加强公平性和顺序,它在Swift中直接使用却是不安全的(参考StackOverFlow讨论)。事实证明,pthread_mutex的底层实现已被更新为os_unfair_lock,而NSLock本身是基于pthread_mutex实现的,因此NSLock是在Swift中锁定的最佳选择。
  • 在调度任务派发后,不要阻塞当前正在等待信号量的线程或者调度组。因为内核不知道哪个线程最终会解除线程阻塞,从而导致执行低效。
  • 不要在非GUI程序和库中使用DispatchQueue.main<dispatch/queue.h>头文件中的解释如下:“ "Because the main queue doesn't behave entirely like a regular serial queue, it may have unwanted side-effects when used in processes that are not UI apps (daemons). For such processes, the main queue should be avoided"。是说主队列并和普通的串行队列不太一样,如果在非UI操作的情况下调用,会导致一些意外情况。具体是啥意外,我还暂时举不出例子。
  • 如果要并行执行,工作项中最好没有资源的竞争,否则性能会急剧下降,竞争有多种形式。加锁来保证线程的安全,但也意味着被竞争的共享资源会成为性能的瓶颈: IPC/daemons, malloc (lock), shared memory, I/O等。
  • 不要一直使用async,这样可以避免线程爆炸。使用少量调度队列来代替DispatchQueue.global()是一个更好的解决办法。
  • 大量异步/回调设计的复杂性(和缺陷)也不容忽视。同步代码仍然更易于阅读、编写和维护。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351