I use String as an identifier for file resource cache lookups.
I’m mildly aware that string is not just a struct, but also references a storage container; like array.
Are there performance hits for transferring Array or String between different actors?
For example does the entire storage get copied every time the array and string are sent? Or does the copy-on-write functionality still hold up across actors?
I’m trying to decide if creating a lookup table actor would be worth my time and energy to reduce copying, if copying would occur.
In CoW containers, isKnownUniquelyReferenced is used under the hood to check an atomic reference count on modification universally, including concurrent access, which is why it is atomic in the first place.
Since you can only directly send immutable values, you can access the same immutable string from any isolation.
var mutable = "foo"
let immutable = mutable // no copy, ref count +1
Task {
// stringConsumer(mutable) <- error, can't send `mutable`
stringConsumer(immutable) // no copies here
var newMutable = immutable // no copy, ref count +1
// creates a copy, `isKnownUniquelyReferenced` is `false` here
newMutable.append("baz")
}
// creates a copy, `isKnownUniquelyReferenced` is `false` here
mutable.append("bar")
Correct! It's thread-safe by virtue of the reference counting being synchronized already. It's just doing a single check, and doesn't also modify the ref count, so there's no TOC/TOU concerns.
By the time you're able to call isKnownUniquelyReferenced(x), you've got a strong reference to x. At that point, it can check if the reference count is >1, indicating that some other reference must exist.