Swift知识碎片: 全局参与者 Global Actor 以及 @MainActor 浅谈

1,264 阅读4分钟

在 Swift 并发模型中,global actor 是一种特殊的 actor,用于确保特定的代码片段在同一个并发上下文(线程或队列)中执行。这与普通的 actor 相似,但作用于全局范围。global actor 主要用于在全局范围内强制任务隔离,特别是对于需要在同一个线程上执行的操作,比如 UI 更新。

1. globalActor 概述

  • global actor 允许我们定义一组代码需要在同一个隔离上下文中执行,确保代码块在相同的 actor 中同步运行。
  • 一个常见的例子是 UIKit 和 SwiftUI 中的 UI 更新,所有的 UI 操作必须在主线程上执行。可以通过 @MainActor 这个全局 actor 来确保 UI 代码在主线程中运行。

2. 使用 @MainActor

@MainActor 是 Swift 中一个预定义的全局 actor,它确保标记的方法、属性或者类在主线程上运行。它非常适合处理 UI 相关的代码,在 iOS 和 macOS 的应用中经常使用。

示例:标记方法为 @MainActor

@MainActor
func updateUI() {
    // 这个函数将在主线程上执行
    print("更新 UI")
}

在上述示例中,updateUI() 函数被标记为 @MainActor,确保它总是在主线程上执行。这对 SwiftUI 和 UIKit 中的 UI 更新非常重要,因为 UI 更新必须在主线程上完成。

3. 自定义 global actor

除了 @MainActor,我们还可以定义自己的全局 actor,用于处理特定的任务隔离。你可以创建自己的 global actor,并将特定代码块分配到该 actor 上,以确保在相同的隔离上下文中执行。

示例:定义自定义的 global actor

actor NetworkActor {}

@globalActor
struct MyGlobalActor {
    static let shared = NetworkActor()
}

在上面的代码中,MyGlobalActor 是一个自定义的全局 actor,所有被标记为 @MyGlobalActor 的代码都会在同一个 NetworkActor 上执行。

使用自定义 global actor

@MyGlobalActor
func performNetworkRequest() {
    // 这个函数将在 MyGlobalActor 的隔离上下文中执行
    print("执行网络请求")
}

现在,performNetworkRequest() 方法会在 MyGlobalActor 的隔离上下文中运行,确保在特定的并发环境下执行所有相关的代码。

4. global actor 的主要用途

global actor 的主要用途是通过任务隔离机制,确保相关代码始终在同一个并发上下文中运行,从而避免数据竞争、线程问题。以下是一些典型应用场景:

  1. UI 更新
    • 使用 @MainActor 确保所有 UI 操作在主线程上进行,避免因线程错误导致的崩溃。
  2. 网络或数据库操作
    • 自定义 global actor 可以确保网络请求、数据库操作等在同一线程或队列中同步运行,避免并发问题。
  3. 全局任务隔离
    • 如果应用程序的某些部分需要全局同步处理,global actor 是确保这些操作在同一上下文中执行的好工具。

5. 如何在代码中应用 global actor

你可以将 @globalActor 属性标记在类、结构体、函数、属性甚至整个模块上,确保这些代码会在相同的 actor 上运行。

示例:标记类为 global actor

@MyGlobalActor
class DataManager {
    func fetchData() {
        print("从数据库获取数据")
    }
}

在这个例子中,DataManager 类中的所有方法都会在 MyGlobalActor 上执行,确保数据获取逻辑在同一个隔离上下文中运行。

6. global actor 与普通 actor 的区别

  • 普通 actor:局部的并发隔离。每个 actor 都是一个独立的隔离域,不同的 actor 可能运行在不同的线程或队列上。它通常用于处理某个具体实例的并发任务。

  • global actor:全局范围的任务隔离。所有使用相同 global actor 的代码都会共享同一个隔离域,确保这些代码在相同的线程或队列中运行。常用于确保某些全局任务(例如 UI 更新)在同一上下文中执行。

7. MainActorglobal actor 的结合

在 iOS 和 macOS 开发中,@MainActor 是最常用的全局 actor,确保所有 UI 更新在主线程上完成。其他场景下,你可以根据业务需求创建自己的 global actor,用于数据同步、网络请求等任务的并发管理。

小结

  • global actor 是 Swift 并发模型中的一种机制,用于在全局范围内强制任务隔离,确保一组代码在同一个并发上下文中执行。
  • @MainActor 是最常用的 global actor,确保 UI 更新在主线程上运行。
  • 你可以自定义 global actor,根据具体场景强制代码执行在特定的隔离上下文中,以避免并发问题。

通过 global actor 的使用,你可以更好地管理代码的并发执行,确保在安全的上下文中完成复杂的异步操作。