Swift多线程开发 - 2. GCD 队列和线程

一个App是 一个进程,一个进程拥有 多个线程。GCD队列负责分配任务到不同的线程上。

多线程的优点:

  • 运行更快. 多线程可以并发处理任务,速度比串行更快
  • 响应. 如果全部任务都在主线程进行,那么在出现比较耗时的任务的时候,用户会明显感觉到卡顿造成较差的用户体验。
  • 优化的资源消耗. 多线程经过操作系统高度优化的,使得线程切换等消耗极小。

1. 基础应用

串行

 let label = "wang.junshuo.example"
 let queue = DispatchQueue(label: label)

并发

 let label = "wang.junshuo.example"
 let queue = DispatchQueue(label: label, attributes: .concurrent)

在推荐的规范中,label的命名采用BundleID似的反域名的方式加上功能名称,比如com.company.app

主队列

应用启动的时候会自动创建负责用户界面的 串行 主队列。
由于使用频率很高,它可以方便的通过DispatchQueue.main类变量访问。

2. 优先级(Quality of service)

不同重要程度的任务通过QoS可以使用不同程度的系统资源和电量,达到高效完成

比如取一个.userInteractive级别的全局队列
let queue = DispatchQueue.global(qos: .userInteractive)

级别

系统预设的优先级有六个。

a. .userInteractive

这个级别的任务设计为处理直接与用户交互相关的任务。比如界面更新计算,动画等。
如果这个任务不马上完成,用户界面看起来就会卡住。所以提交到这个队列任务需要立即完成.

b. .userInitiated

这个级别的任务设计为处理需要立即发生但是可以异步完成。比如从用户点击查看一个文档,或者从本地数据库读取信息等。
这里的任务也期望短时间或几秒内迅速完成。

c. .default

这个选项是默认值,是作为没有明确设定优先级的时候的缺省值。最好给每个任务都设定一个级别而不是使用这个值。

c. .utility

这个级别的任务设计为用于长时间运行的计算等。比如联网或连续数据馈送。
任务会在响应速度和性能与能源效率之间取得平衡。这里的任务可能需要几秒钟到几分钟。

d. .background

这个级别的任务设计为用于花费长时间并且用户不在乎它什么时候完成的。比如数据库维护,同步远程服务器和备份。
这里的任务将专注于能源效率而不是速度,那些用大量时间(几分钟或更长)的工作应该放这里。

e. .unspecified

这个选项是用于兼容旧版API,因为有些旧版API可能会使线程超出QoS范围。所以不要使用这个值。

优先级推断

如果加入队列的任务优先级比队列高,那么队列中以及其包含的所有任务的优先级也会自动提升到这个优先级。

3. 添加任务

比如添加一个网路请求任务然后刷新

DispatchQueue.global(qos: .utility).async { [weak self] in
    guard let self = self else { return }
    // 网络请求代码

    // 切换到主线程刷新任务
    DispatchQueue.main.async {
        self.textLabel.text = "JuHub又更新了哇!" 
    }
}

注意点

上述代码有两点值得注意

a. Weak Self

GCD是不会造成循环引用的, 但是在GCD的闭包中强引用self会使得self更晚被释放(直到网络请求完成才会释放)。
比如在一个将要被dismissviewController中网络请求还没有完成,则弱引用selfviewController会被直接释放(如果没有其它循环引用),而强引用的viewController直到网络请求完成才会释放。

具体要不要弱引用self完全取决于业务需求

b. 主线程刷新

通常我们都是在网络请求完之后异步刷新主线程。使用sync要非常注意,因为一旦错误的调用比如在当前线程同步任务中访问同步队列中的资源,那么当前线程就会造成死锁问题。

在主线程添加同步任务会造成主线程死锁

更进一步的,在上一篇中我们讲过无法确定队列中的任务最终会被分配到哪个线程,所以在你创建了一个自定义队列然后添加同步任务的时候,这个同步任务可能还是在主线程执行。而此时如果在这个自定义队列里DispatchQueue.main.sync(){}就会造成死锁

func test() {
    let queue = DispatchQueue(label: "wang.junshuo.example.testQueue")

    print("1\(Thread.current)") // Main Thread

    queue.sync {
        print("2\(Thread.current)") // Main Thread 
        DispatchQueue.main.sync {
            print("3\(Thread.current)") // Main Thread. 死锁
        }
    }
}

所以执行同步任务的时候要十二分的谨慎。



作者博客地址

系列文章链接

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

推荐阅读更多精彩内容