摸鱼精选第 21 期

1. 现代化工具链在大规模 C++ 项目中的技术实践

现代的 C++工具链一般就是指 LLVM,传统的是 GCC。当从 GCC 切换到最新的 LLVM,除了能使用 C++最新的语言版本、特性,比如 Coroutines, Modules

  • ThinLTO: link 优化,性能提升 10%
  • AutoFDO: 先编译一个没有开启 AutoFDO 的版本,收集线上的性能采集数据,然后使用 AutoFDO 编译另一个版本,性能提升 2%~5%
  • Bolt:性能提升 8%

2. 掌握 SwiftUI 的 task 修饰器

结合另一篇文章阅读:Where View.task gets its main-actor isolation from

.task(priority:_:) 中的优先级不改变创建任务时所使用的线程,即使是.background 也不不表示就是在后台线程。

task 的 action@_inheritActorContext修饰,闭包将根据其声明的地点来继承 actor 上下文( 即它应该在哪个 actor 上运行 )。那些没有特别声明需运行在某特定 actor 上的闭包,它们可以运行于任意地点( 任何的线程之中 )。由于 View 协议限定了 body 属性必须运行于主线程中( 使用了 @MainActor 进行标注 ),因此,如果我们直接在 body 中为 task 修饰器添加闭包代码,那么该闭包只能运行于主线程中。如果我们想让 task 修饰器中的闭包不运行在主线程上,只需要将其声明在没有要求运行于 @MainActor 的地方即可。

struct TimerView: View {
  var body: some View {
    VStack {
      Text("test")
        .task(timer)
    }
  }

  @Sendable
  func timer() async {
    //...
  }
}

务必注意,如果将 .task(timer) 写为 .task{ await timer() } ,则仍会运行于主线程中。

Swift 采用的是协作式任务取消机制,也就是说,SwiftUI 是无法直接停止掉我们通过 task 修饰器创建的异步任务的。当满足了需要停止由 task 修饰器创建的异步任务条件时,SwiftUI 会给该任务发送任务取消信号,任务必须自行响应该信号并停止作业。

在以下两种情况下,SwiftUI 会给由 task 创建的异步任务发送任务取消信号:

视图( task 修饰器绑定的视图 )满足 onDisappear 触发条件时 绑定的值发生变化时( 采用 task 观察值变化时 )

3. Blogged Answers: A (Mostly) Complete Guide to React Rendering Behavior

基于最新的 React 18,梳理了一遍 React 渲染过程。

4. RFC: File System-Based Native Routing with Expo and React Native

Web 端的路由是非常灵活的,但是要移植到 APP 端就很难,因为 Android 和 iOS 的原生路由系统区别很大。很多原生路由的内部状态是很难通过 URL 参数来表示的。

Expo 提出一种基于文件系统的本地路由,用于 Expo 和 React Native。这种方式在后端开发上较常见,相比传统的路由会更加清晰,文件结构就能看出路由了。另外底层基于 React Navigation,也方便迁移。

5. 推荐 12 个值得学习的 TypeScript 宝库!

TypeScript 开源文档。

6. 使用 TypeScript 编写 React 的最佳实践!

如题。

7. 谈谈 JS 二进制:File、Blob、FileReader、ArrayBuffer、Base64

在 Web 端操作文件的机会不是很多,大部分是使用 File 来上传文件。但在 Node 里就会遇到各种文件操作,不同的内置文件对象对应不一样的用途。

8. 深入理解 Android Studio Sync 流程

本文首先介绍了 Android Studio Sync 流程中各个角色的作用及联系,对 Sync 有一个较清晰的整体认识,然后从源码角度深入分析从触发 Sync 入口到 Gradle 构建结束的阶段,并详细解释了 Gradle Model、BuildAction 等关键概念,最后分别从 Android Studio 视角和 Gradle 视角对 Sync 流程进行了整体梳理。

通过对 Android Studio Sync 流程的深入分析,除了对 Sync 功能的实现原理深度掌握外,对其意义也有了更深的理解。Sync 是 Android Studio 定义的一个 IDE 准备阶段,在这个准备阶段中,需提前准备好关键的 IDE 功能,而这些功能要达到可用状态,需要获取其必需的数据。基于这个角度,对 Sync 流程的优化方向也有了一定启发:首先从产品层面出发考虑 Sync 阶段的定义,不是开发者真正必需的功能都可以考虑省略或延后准备;然后确认必需功能所需的最小数据集,不必需的数据都可以省略;最后针对必需数据,通过更高效的实现或缓存,找到最快的获取方式。

9. Android 蓝牙协议栈漏洞剖析

Android 系统中蓝牙协议栈演进分为几个阶段,最早 android 使用是 Linux 蓝牙协议栈 BlueZ。从 Android 4.2 开始,Google 便在 Android 源码中推出了它和博通公司一起开发的 BlueDroid 以替代 BlueZ。当前 Android 使用的蓝牙协议栈版本名为 Fluoride,而 Google 正在开发的下一代蓝牙协议栈叫做 Gabeldorsh,并使用 Rust 编程语言进行开发。目前 Fluoride 蓝牙协议栈基本上还是使用 C/C++语言来实现的,由于蓝牙报文的协议解析处理涉及大量的内存操作,加上蓝牙协议的多样性和复杂性,以及历史上多家公司代码融合等各类原因,导致安卓蓝牙协议栈爆出过很多严重 RCE 漏洞。而 Gabeldorsh 可以利用 Rust 语言本身的特性减少内存型漏洞的产生。这就导致今后对蓝牙协议栈的漏洞挖掘更会集中于逻辑性漏洞,如协议本身的逻辑问题、条件竞争、设计缺陷等方面,这就更加要求该领域的漏洞挖掘研究员具有更加深厚的蓝牙技术知识栈,漏洞挖掘的技术门槛也会更高、需要突破的难点也会更多。

10. eBPF 在大厂的应用

本节介绍了我们的基于 BPF_PROG_TYPE_SK_REUSEPORT 和 BPF_MAP_TYPE_REUSEPORT_SOCKARRAY 实现的新一代发布技术,它能实现主机内新老实例流量的无损切换,优点:

  • 简化了运维流程,去掉脆弱和复杂的进程间通信(IPC),减少了故障;
  • 效率大幅提升,例如 UDP 性能 10x;
  • 可靠性提升,例如避免了 UDP misrouting 问题和 TCP 三次握手时的竞争问题。