brennanMKE
(Brennan Stehling)
1
I've created this experiment. while ActorCounter is often more consistent than ClassCounter it is often not correct. Are static properties protected or not by actors?
import Foundation
let max = 1_000
actor ActorCounter {
static var count: Int = 0
static func increment() async {
count += 1
}
}
class ClassCounter {
static var count: Int = 0
static func increment() {
count += 1
}
}
// Increment concurrently using a Task Group
await withTaskGroup(of: Void.self, body: { group in
for _ in 0..<max {
group.addTask {
await ActorCounter.increment()
}
}
})
// Increment concurrently using Dispatch
DispatchQueue.concurrentPerform(iterations: max) { _ in
ClassCounter.increment()
}
print("Concurrent Perform is done")
var count = 0
for _ in 0..<max {
count += 1
}
// make sure the work is really completed
let nanoseconds = UInt64(0.25 * Double(NSEC_PER_SEC))
try await Task.sleep(nanoseconds: nanoseconds)
print("Actor:", ActorCounter.count)
print("Class:", ClassCounter.count)
print("Non-Async:", count)
1 Like
Joe_Groff
(Joe Groff)
2
Static methods are not part of any actor instance; they're global state just like static properties on other types. I wouldn't expect any reliable difference between the ActorCounter or ClassCounter here. If you want an actor guard that isn't tied to any particular instance, you can define a global actor, like MainActor, and decorate the methods you want to be guarded by it with the attribute for the global actor.
2 Likes
brennanMKE
(Brennan Stehling)
4
Instead of implementing a Global Actor, which requires Xcode 13, I have made it into a singleton since we still need to allow Xcode 12.4 to be used.
Using @MainActor on that shared property should work, right?
@MainActor
static let shared = MyType()
Jon_Shier
(Jon Shier)
5
@MainActor is also Xcode 13+. If you need to support Xcode 12 / Swift <= 5.4, you have conditionalize all of your concurrency usage behind a check.
Edit: It may look like @MainActor is available but that's a compiler bug that's fixed on main but not yet in a release. Narrowly avoided that one myself.
2 Likes
brennanMKE
(Brennan Stehling)
6
What I've read here says custom global actors were possible with Xcode 13. I will have to try this out with Xcode 12.4, but I believe we have used @MainActor before. We have not created a custom global actor yet.
Jon_Shier
(Jon Shier)
7
@MainActor is a global actor.
brennanMKE
(Brennan Stehling)
8
It is a special case which was supported earlier than the custom global actors, if what I am reading is accurate.
Jon_Shier
(Jon Shier)
9
@MainActor was available slightly before the ability to define your own global actors, but both were generally part of Xcode 13 / Swift 5.5.
brennanMKE
(Brennan Stehling)
10
Wait, nevermind. All these versions are very confusing. I am using Xcode 14 and we support back to Xcode 13.4.