In Swift concurrency, tasks are run by threads from the Swift concurrency cooperative thread pool. When a task suspends at an await, the thread running that task returns to the thread pool and looks for more work to do.
Thanks for the clarity here. This is what I was attempting to say with "and the thread continues on" 😅
I don’t understand what you mean by this. When the thread returns to the thread pool, it gives up the actor’s context. At this point other threads are able to enter the actor.
I thought when you would do let (data, response) = await urlSession.data(for: request) the continuation wrapper around dataTask(with:completionHandler:) created a Task under the hood that would run on the actor. After reading the docs more it states that a continuation wrapper will suspend the current task and then call the closure with checked throwing continuation for the current task. So basically whatever is run inside the closure is done outside of the swift concurrency world until the continuation is called informing swift concurrency the task is ready to run again.
Are there any major tradeoffs to using the nonisoalted approach above? I was using the new Swift Concurrency instrument tool to test the Networking actor above using the following code:
func runTest() {
Task {
try! await withThrowingTaskGroup(of: Void.self) { group in
for i in 0..3 {
group.addTask {
try await networking.data(from: URLRequest(url: URL(string: "https://www.google.com")!))
}
}
try await group.waitForAll()
}
}
}
I noticed if the networking.data(from:) function did not have the nonisolated keyword the created Tasks had more time spent in the enqueued state than if I added the nonisolated keyword. I was not sure why this occurred, or if this was even truly a problem. The Tasks still all ran in parallel.