了解GlobalActor,是否保证它不会在主线程上执行

Anu*_*yal 6 actor ios async-await swift

我正在学习 的用法,async-await并同时阅读有关Global Actors. 我知道的MainActorGlobalActor,如果我们用注释一个方法@mainActor,该方法将在主线程上执行。类似于如果我们创建一个自定义的 GlobalActor,我们是否知道它将使用哪个线程来执行。

@globalActor actor CustomGlobalActor {
     static let shared = CustomGlobalActor()
 }

@CustomGlobalActor func performTask() async -> Output {
    .....
}
Run Code Online (Sandbox Code Playgroud)

另外,补充问题:

  1. 我们可以互换使用它来在后台线程中执行耗时的任务吗?
  2. 它是否以任何方式连接到全局队列?

Rob*_*Rob 11

一些观察:

\n
    \n
  1. \xe2\x80\x9cglobal actor\xe2\x80\x9d (如SE-0316中定义)只是一个可全局访问的命名actor 。如果您定义自己的全局参与者,则可以在整个应用程序中通过该名称全局访问该特定参与者。

    \n

    我知道你知道这一点,但主角也是一位全球演员。它只是一种特殊的、预定义的、恰好依赖于主线程的线程。(类似于GCD\xe2\x80\x99s \xe2\x80\x9cmainqueue\xe2\x80\x9d只是一个恰好使用主线程的特殊调度队列。)

    \n

    但是,请注意,当人们开始担心特定参与者上的特定任务正在使用哪个线程时,该参与者是否是全局参与者并不重要。我们\xe2\x80\x99只关心此时演员的行为。出于本次对话的目的,我们并不特别关心参与者是否是全局参与者。仅仅因为它是一个演员。

    \n
  2. \n
  3. 可能不用说,此时 \xe2\x80\x9cglobal actor\xe2\x80\x9d 的 \xe2\x80\x9cglobal\xe2\x80\x9d 与 GCD \xe2\x80\x9cglobal\xe2 无关\x80\x9d 调度队列。它们是完全不同的概念。

    \n
  4. \n
  5. 你说:

    \n
    \n

    类似于如果我们创建一个自定义的 GlobalActor,我们是否知道它将使用哪个线程来执行。

    \n
    \n

    这有点吹毛求疵,但是,不,除了主要参与者(与主线程相关)之外,一般参与者并不与特定线程相关。(无论如何,Swift 并发努力将我们从线程级细节中抽象出来。)

    \n

    正如人们应该避免将线程和 GCD 调度队列混为一谈一样,actor 也是如此。如果您已将三个任务提交给某个非主要参与者,则您无法保证它们将在同一线程上运行。您只知道无论它们在什么线程上运行,该参与者上的不同任务都不会与同一参与者上的其他任务同时主动运行。由于特定参与者上的任务不会并行运行,因此它们很可能最终在同一线程上依次运行。但他们可能不会。

    \n

    如果您对这些详细信息感兴趣,请参阅 WWDC 2021 Swift 并发:幕后花絮

    \n
  6. \n
  7. 是的,在实践中,在非主参与者(无论它是否恰好是全局参与者)上运行的任务用于从主线程获取耗时的同步任务(例如某些计算密集型进程) 。

    \n

    但这并不是演员的主要目的。它们\xe2\x80\x99更多的是允许我们管理不同任务之间的一些可变共享状态。请参阅 WWDC 2021使用 Swift Actor 保护可变状态

    \n

    所以,如果你有一个计算密集型的计算,你想摆脱主线程,是的,理论上你可以使用演员。如果您希望该演员成为全球演员,您也可以这样做(尽管这种情况不太常见)。但是,如果您想做的只是从主线程中获取一些计算密集型进程,您可能只使用async非隔离函数(请参阅SE-0338)或分离任务,然后就到此为止了。Actor 更多的是管理跨任务的状态,而不是从主线程中获取某些东西。

    \n
  8. \n
  9. 你问:

    \n
    \n

    我们可以互换使用它来在后台线程中执行耗时的任务吗?

    \n
    \n

    人们应该警惕那些在async-中不包含任何暂停点的耗时任务await。快速并发强加了一个永远不会阻碍前进的契约。如果您想要在 Swift 并发中运行一些缓慢的同步任务,则行为良好的例程会定期执行Task.yield。请参阅/sf/answers/5366571801/

    \n
  10. \n
\n