Sorry for not being more concrete but I'm still not really sure what you are trying to accomplish.
But you can already do that. Since main
is async your entire program is in an async context you can freely call async functions.
I do think is the solution but probably I'm not understanding the problem.
Yes totally, if you need to wait for async work you need to be in an async context, but again, your main program is already async so you can do that already.
As I said, maybe I'm not understanding the problem but let me try to again anyway ;)
You have an actor that protects access to a resource (the spoke
variable in this case)....
actor AsyncSayer {
var spoke = 0
func say(_ text: String) {
spoke += 1
print("Say: \(text).\t Spoke \(spoke) times.")
}
}
Then you want to perform some piece of work (workAsync
in this case)....
func workAsync(_ id: String, asyncSayer: AsyncSayer) async {
for i in 1...3 {
await asyncSayer.say("\(id) #\(i)")
try? await Task.sleep(nanoseconds: 1 * NSEC_PER_SEC) // simulating some real work
}
}
Note that I replaced the sleep with a proper Task.sleep.
Then I'm assuming the workItem
is the input of your work, and that the array comes from some other place that makes it dynamic...
So since your "input" is variable you need to use a TaskGroup
to perform async work concurrently. (if you know you just want to run 2 things concurrently you can use async let
instead.)
await withTaskGroup(of: Void.self, body: { group in
for item in workItems {
group.addTask {
await workAsync(item, asyncSayer: actor)
}
}
})
The full code
@main
enum App {
static func main() async throws {
let workItems = ["A", "B"]
let actor = AsyncSayer()
await withTaskGroup(of: Void.self, body: { group in
for item in workItems {
group.addTask {
await workAsync(item, asyncSayer: actor)
}
}
})
}
}
func workAsync(_ id: String, asyncSayer: AsyncSayer) async {
for i in 1...3 {
await asyncSayer.say("\(id) #\(i)")
try? await Task.sleep(nanoseconds: 1 * NSEC_PER_SEC) // simulating some real work
}
}
actor AsyncSayer {
var spoke = 0
func say(_ text: String) {
spoke += 1
print("Say: \(text).\t Spoke \(spoke) times.")
}
}
Running this prints:
Say: B #1. Spoke 1 times.
Say: A #1. Spoke 2 times.
Say: B #2. Spoke 3 times.
Say: A #2. Spoke 4 times.
Say: B #3. Spoke 5 times.
Say: A #3. Spoke 6 times.
Which shows how each workAsync
happens concurrently while keeping the access to the counter protected.
Isn't that what you want? ^^