我理解所有在actor内部的并行工作在某种程度上变成了串行的,作为某种同步过程的一部分。我们可以看到,应该并行完成的async let-work在Actor 1中顺序完成,很可能是由于actor的内部同步。但是,withTaskGroup-work并行运行,尽管AnActor内部同步,但为什么?)
编辑:同时,我想说,当使用await时,我理解从actor内部外部调用同步是如何工作的,但我不理解在actor内部同步是如何工作的,在actor内部调用异步并行任务。
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView().task {
//await AnActor().performAsyncTasks() // uncomment this alternately and run
//await Actor1().performAsyncTasks() // uncomment this alternately and run
}
}
}
}
actor Actor1 {
func performAsyncTasks() async {
async let _ = asyncTasks1() // this not running in parallel
async let _ = asyncTasks2() // this not running in parallel
}
func asyncTasks1() async {
for i in 1...10_000_0 {
print("In Task 1: \(i)")
}
}
func asyncTasks2() async {
for i in 1...10_000_0 {
print("In Task 2: \(i)")
}
}
} // the printed text are in series with Task 1 and Task 2 in console
actor AnActor {
var value = 0
func performAsyncTasks() async {
value = await withTaskGroup(of: Int.self) { group in
group.addTask { // this running in parallel, why?!
var value1 = 0
for _ in 1...10_000 {
print("Task1")
value1 += 1
}
return value1
}
group.addTask { // this running in parallel, why?!
var value2 = 0
for _ in 1...10_000 {
value2 += 1
print("Task2")
}
return value2
}
return await group.reduce(0, +)
}
print(value)
}
} // the printed text are mixed with Task 1 and Task 2 in console
2条答案
按热度按时间0h4hbjxa1#
考虑你的第一个例子:
你说:
我们可以看到,应该并行完成的
async let
工作在Actor1
中顺序完成。是的,通常
async let
可以让例程并发运行。但这里不会发生这种情况,因为这两个函数都是独立于同一个参与者的,并且没有await
挂起点。有人说:
如果
async let
是let _ = await asyncTasks1()
的简写方式…它不是。参见SE-0317。
如果你想看到并行执行,你可以使用
async let
。你只需要使用非隔离函数:如果我在仪器中分析它,我可以看到它们并行运行:
顺便说一下,上面使用了以下POI实用函数:
ki1q1bka2#
您看到的行为是由于您正在执行的异步任务的性质,当该任务绑定到
Actor
时。iOS中的底层线程执行模型不允许抢占。也就是说,CPU永远不会从任务中“拿走”。当一个任务放弃CPU时,其他任务就有机会开始执行。
此代码:
is CPU bound -在
for
循环完成之前,没有机会在Actor上运行任何其他任务。Async/Await通常用于存在一些异步操作的地方;例如,网络操作。
如果我们对您的功能做一个小的更改:
您将看到两个函数的输出混合在一起,因为每个函数在每个
print
之后都放弃了CPU,允许actor执行另一个函数,直到 it 放弃CPU。现在,至于为什么你看到
withTaskGroup
的不同行为-这是因为任务组没有绑定到Actor
,即使你是在一个绑定到Actor
的函数中创建它。任务组可以使用多个线程来执行任务。这是它的主要功能,允许一系列独立的操作在它们全部完成(或取消)时以简单的集合执行。如果删除添加的
await sleep
并对任务组代码进行小更改:现在您将看到两个循环顺序完成,因为它们绑定到
Actor1
示例。