Edit: to clarify I was thinking about a mutable context share as shown in the code example, not solely about the ref counting.
Edit: to clarify I was thinking about a mutable context share as shown in the code example, not solely about the ref counting.
By not using reference counting. State of the art GCs don’t count references. They usually doing mark and sweep, implementing multiple generations, and/or doing a few other things.
Most of that overhead only happens while collecting. Merely referencing an object from another thread doesn’t modify any shared cache lines.
> What language has a sufficiently lock less rw capable GC?
Java, C#, F#, Golang.
But if it's just for the ref counting part of the Arc then I can see how a GC would solve it by not needing the RC
A quote from the article: “No locks, no mutexes, no syscalls, no shared mutable data here. There are some read-only structures context and unit shared behind an Arc, but read-only sharing shouldn’t be a problem.” As you see, the data shared across threads was immutable.
However, the library they have picked was designed around Rust’s ref.counting Arc<> smart pointers. Apparently for some other use cases, not needed by the OP, that library needs to modify these objects.
> I can see how a GC would solve it by not needing the RC
Interestingly enough, C++ would also solve that. The language does not stop programmers from changing things from multiple threads concurrently. For this reason, very few libraries have their public APIs designed around std::shared_ptr<> (C++ equivalent of Rust’s Arc<>). Instead, what usually happens, library authors write in the documentation things like “the object you pass to this API must be thread safe” and “it’s your responsibility to make sure the pointer you pass stays alive for as long as you using the API”, and call it a day.
Technically, all programming languages are Turing-complete. Practically, various things can affect development cost by a factor of magnitude. The OP acknowledges that, they wrote "Rewriting Rune just for my tiny use case was out of the question".
Just because something can be done doesn't mean it's a good idea to do that. Programming is not science, it's engineering, it's all about various tradeoffs.
> The language just steers you away
Such steering caused unique performance issues missing from both safer garbage collected languages, and unsafe C++.
Note the OP was lucky to be able to workaround by cloning the data. If that context or unit objects would use a gigabyte of RAM, that workaround probably wouldn't work, too much RAM overhead.
Doing that is prohibitively expensive in this particular case. It would require patching a large third-party library who uses Arc for the API: https://docs.rs/rune/latest/rune/struct.Vm.html#method.new
And the reason that library uses Arc in the API is unique to Rust.
A different non-GC language wouldn't change things, because you'd have the exact same trade off if the same decision was made.
The only major difference is that Rust pushes you to Arc but C++ doesn't push you to a shared_ptr.
https://blog.twitch.tv/en/2016/07/05/gos-march-to-low-latenc...
----------
I'm familiar with Go's GC. Your linked post doesn't explain how it would avoid the hit mentioned by the cache invalidation across multiple clusters.
It'll either try and put multiple go routines on a single cluster (as listed in the link) or it'll need to copy the necessary stack per thread. Which is effectively what the original article ends up doing.
But if you encounter anything that needs to run concurrently across threads while using a single r/w object, you'll hit the same cliff surely?