惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
T
The Blog of Author Tim Ferriss
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网
爱范儿
爱范儿
GbyAI
GbyAI
H
Help Net Security
I
InfoQ
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
N
Netflix TechBlog - Medium
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
云风的 BLOG
云风的 BLOG
Project Zero
Project Zero
P
Privacy & Cybersecurity Law Blog
A
Arctic Wolf
Know Your Adversary
Know Your Adversary
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tor Project blog
V
Vulnerabilities – Threatpost
Y
Y Combinator Blog
WordPress大学
WordPress大学
V
Visual Studio Blog
博客园_首页
G
GRAHAM CLULEY
K
Kaspersky official blog
T
Tailwind CSS Blog
T
Threat Research - Cisco Blogs
博客园 - Franky
D
Docker
Security Latest
Security Latest
I
Intezer
有赞技术团队
有赞技术团队
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 【当耐特】
B
Blog RSS Feed
T
The Exploit Database - CXSecurity.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Origin

Agent 安全:环境变量泄露 人生第一次离职,感觉应该写点什么 在 Python 中复现 Race Condition 再看看 SQL 中的 null 迁移 Zeabur 集群 2025Q3 订阅 Recap 再见 xlog Python 的 pth 文件:在程序启动前自动执行命令 浏览器从 A 到 Z 2024Q3 订阅 Recap 使用 TypeScript 撰写 OmniFocus 脚本 [备忘] Go init 行为 [随笔] 一开始就公布定价 [随笔] Server Action [随笔] RSS 与稍后阅读 在 Shell 脚本中嵌入二进制文件 谈谈时区 利用 Fly.io 部署 Windmill 强制关闭 xLog 的 Dark Mode 解决 CentOS8 中 yum 源失效 [随笔] 避免完美主义导致的看似时间不够
[随笔] Swift 异步:Task vs DispatchQueue
Singee · 2023-09-21 · via Origin

本文同步自「我的 Memos - 随笔」,你也可访问 x.singee.me 查看我的全部碎碎念

在 Swift 上,执行一个异步的函数大体上有两种办法

  • Task
  • DispatchQueue

背景知识:线程和队列

Swift 同时支持多线程和异步,因此

  • 存在主线程和多个后台线程
  • 每个线程存在若干队列(若干个全局 global 队列(每个优先级一个)、自定义队列(人为创建))

背景知识:队列优先级

在队列层面,存在优先级的概念(在 Task 中叫 priority,在 DispatchQueue 中叫 qos)

  • userInteractive:最高优先级,适用于 UI 操作(例如动画等)(在 Task 中被弃用)
  • userInitiated:较高优先级,适用于用户触发的操作
  • default:中优先级,默认(在 Task 中被弃用)
  • high, medium, low:高中低优先级(仅在 Task 中存在)
  • utility:较低优先级,适用于耗时的后台任务
  • background:最低优先级,适用于耗时的后台任务
  • unspecified:继承于 Thread.current.qualityOfService(在 Task 中被弃用)

背景知识:main

main 同时隐含着两个概念:main thread 和 main queue,事实上无需特意区分(可以认为只有 main thread 才有 main queue,而 main thread 的不同 queue 之间并无特殊区别)

main 的主要用处在于其是直接和用户交互的,只有在 main 才能修改 UI、如果 main 繁忙用户会感觉到 UI 刷新卡顿

  • 对于 Task 而言,在 main 执行使用 Task { @MainActor
  • 对于 DispatchQueue 而言,在 main 执行使用 DispatchQueue.main

注意,Task 的 @MainActor 实际上并不是让闭包代码在 main 执行,而是让其他执行它的 concurrency-aware 代码逻辑在 main 上执行(但是目前存在非 concurrency-aware 的代码,因此可能标记了 @MainActor 实际上仍然是在非 main 执行的,这种时候需要手动切换到 main;不过这种情况 XCode 会有警告,所以不必过于担心)

DispatchQueue 相关

  • 依赖的是 Grand Central Dispatch(GCD) libdispatch
  • Dispatch.main 是在主线程执行的,其他均不保证实际执行线程
  • 执行顺序先进先出
  • 队列类型分为 serial 和 concurrent 两种,serial 在执行完一个任务后才会开始执行另一个、concurrent 会同时执行多个任务(故不保证任务的结束顺序);main 是 serial 类型的、默认也是 serial 类型的
  • 执行时存在 sync 和 async 两种,sync 会等待这个任务完成后返回,async 会直接返回
  • 因上述特性,在 main 线程执行 DispatchQueue.main.sync 会导致死锁
  • 无法直接获得执行结果

Task 相关

  • Task 有 child 和 detached 两种类型,区别在于后者无法访问到调用方可见的变量
  • 来自于 main 创建的 child Task 会始终在 main 执行,否则(除非标记 @MainActor)不保证执行的线程/队列
  • 已提交的任务可取消、可获取(等待)结果(获取结果需要 await)
  • 如果和 DispatchQueue 类比,可以认为 Task 与 DispatchQueue.async 执行上的行为一致

额外:RunLoop

  • RunLoop.current 返回当前的线程循环、.main 返回主线程循环
  • 通常情况下,无需特别注意 RunLoop.main 和 DispatchQueue.main 的区别,二者都是在 main 上执行逻辑
  • RunLoop.main 中执行的逻辑可以被外部用户操作暂停,而 DispatchQueue.main 不会,因此在处理滚动时可能更希望使用 RunLoop.main,而其他通常场景则一般使用 DispatchQueue.main