From: "ianks (Ian Ker-Seymer)" Date: 2022-07-23T02:34:55+00:00 Subject: [ruby-core:109308] [Ruby master Feature#18926] Ractor should support mutexes and treat the block as critical section across ractors Issue #18926 has been updated by ianks (Ian Ker-Seymer). With all due respect for Ractor���s incredible technical achievements so far, I unfortunately think that the ���honeymoon phase��� for Ractor may be complete. The community was incredibly bullish about its potential and the problems it could solve, but so far it has proven to be too burdensome. I could be misinformed, but I personally don���t know of any serious projects making use of Ractor for this reason. It���s unfortunate, but not all hope is lost��� I think it would be wise to honestly examine the shortcomings of Ractor. And if needed, entirely re-design to make it more useful to the Ruby community. If that isn���t possible, we should explore ways to communicate the shortcomings, and provide a clear path and solutions for these common issues. A lot of hard work and technical accomplishments have gone into making Ractor even possible, and I have a deep respect for it. I am just worried Ruby users might lose faith in it. ---------------------------------------- Feature #18926: Ractor should support mutexes and treat the block as critical section across ractors https://bugs.ruby-lang.org/issues/18926#change-98444 * Author: chucke (Tiago Cardoso) * Status: Open * Priority: Normal ---------------------------------------- This is an improvement suggestion in order to foster adoption of ractors. It may not be technically impossible or unfeasible for some reason, as it may lead to deadlocks, so feel free to discard it if massively hard to undertake. There's a pattern, common to a lot of popular gems, and stdlib, in the wild, which I call "lazy-load-then-cache". Essentially, smth like: ```ruby class A @map = {} @map_mutex = Mutex.new def self.set_in_map(name, value) @map_mutex.synchronize do @map[name] = value end end def self.get_from_map(name) if not @map.key?(name) value = do_smth_heavy_to_figure_out(name) set_in_map(name, value) value else MAP[name] end end end ``` The main issues here regarding ractor safety are: * MAP is not frozen * ractor does not support usage of mutexes Examples: * sequel: https://github.com/jeremyevans/sequel/blob/master/lib/sequel/database/connecting.rb#L76 * resolv: * https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L187 (instance-based variation of the above) * https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L1341 (not protected by mutex, but still a usage of a global counter) While I've found [a gem implementing a ractor-aware cache](https://github.com/ractor-tools/ractor-cache), while looking a bit outdated, it also makes use of `ObjectSpace::WeakMap`, which is probably a dealbreaker and a "hack" around ractor's limitations. It's also not necessarily a "drop-in" replacement for the pattern exemplified above. ---- Theoretically, ractor could support the pattern above, by allowing the usage of mutexes. It should however run mutex blocks exclusively across ractors, while also disabling "ractor checks". This means that a mutable MAP could be mutated within a ractor, as long as protected by a mutex. However, it should be marked as frozen before the block terminates. So the code above should be modified to: ```ruby @map = {}.freeze @map_mutex = Mutex.new def self.set_in_map(name, value) @map_mutex.synchronize do @map = @map.merge(name => value) @map.freeze end end ``` ---- Again, there may be implementation limitations not enabling usage of such a pattern. But it's a telling sign when ractors can't support simple usages of stdlib. So this proposal aims at enabling yet another case which may diminish the overhead of supporting ractors going forward, thereby making ractors usable in more situations. -- https://bugs.ruby-lang.org/ Unsubscribe: