mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/psych] Make Ractor-ready.
Config is Ractor-local. Benchmarking reveals that using `Ractor.local_storage` for storing cache is similar to accessing a constant (~15% slower).
This commit is contained in:
parent
3ee0ad9190
commit
c5a445d577
Notes:
git
2020-12-23 15:09:02 +09:00
4 changed files with 90 additions and 6 deletions
|
@ -632,9 +632,29 @@ module Psych
|
||||||
private_class_method :warn_with_uplevel, :parse_caller
|
private_class_method :warn_with_uplevel, :parse_caller
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_accessor :load_tags
|
if defined?(Ractor)
|
||||||
attr_accessor :dump_tags
|
require 'forwardable'
|
||||||
attr_accessor :domain_types
|
extend Forwardable
|
||||||
|
|
||||||
|
class Config
|
||||||
|
attr_accessor :load_tags, :dump_tags, :domain_types
|
||||||
|
def initialize
|
||||||
|
@load_tags = {}
|
||||||
|
@dump_tags = {}
|
||||||
|
@domain_types = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def config
|
||||||
|
Ractor.current[:PsychConfig] ||= Config.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def_delegators :config, :load_tags, :dump_tags, :domain_types, :load_tags=, :dump_tags=, :domain_types=
|
||||||
|
else
|
||||||
|
attr_accessor :load_tags
|
||||||
|
attr_accessor :dump_tags
|
||||||
|
attr_accessor :domain_types
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self.load_tags = {}
|
self.load_tags = {}
|
||||||
self.dump_tags = {}
|
self.dump_tags = {}
|
||||||
|
|
|
@ -8,12 +8,26 @@ module Psych
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
DISPATCH = Hash.new do |hash, klass|
|
# @api private
|
||||||
hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
|
def self.dispatch_cache
|
||||||
|
Hash.new do |hash, klass|
|
||||||
|
hash[klass] = :"visit_#{klass.name.gsub('::', '_')}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if defined?(Ractor)
|
||||||
|
def dispatch
|
||||||
|
Ractor.current[:Psych_Visitors_Visitor] ||= Visitor.dispatch_cache
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DISPATCH = dispatch_cache
|
||||||
|
def dispatch
|
||||||
|
DISPATCH
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def visit target
|
def visit target
|
||||||
send DISPATCH[target.class], target
|
send dispatch[target.class], target
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,9 @@ VALUE mPsych;
|
||||||
|
|
||||||
void Init_psych(void)
|
void Init_psych(void)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
||||||
|
RB_EXT_RACTOR_SAFE(true);
|
||||||
|
#endif
|
||||||
mPsych = rb_define_module("Psych");
|
mPsych = rb_define_module("Psych");
|
||||||
|
|
||||||
rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0);
|
rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0);
|
||||||
|
|
47
test/psych/test_ractor.rb
Normal file
47
test/psych/test_ractor.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
require_relative 'helper'
|
||||||
|
|
||||||
|
class TestPsychRactor < Test::Unit::TestCase
|
||||||
|
def test_ractor_round_trip
|
||||||
|
assert_ractor(<<~RUBY, require_relative: 'helper')
|
||||||
|
obj = {foo: [42]}
|
||||||
|
obj2 = Ractor.new(obj) do |obj|
|
||||||
|
Psych.load(Psych.dump(obj))
|
||||||
|
end.take
|
||||||
|
assert_equal obj, obj2
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_shareable
|
||||||
|
# There's no point in making these frozen / shareable
|
||||||
|
# and the C-ext disregards begin frozen
|
||||||
|
assert_ractor(<<~RUBY, require_relative: 'helper')
|
||||||
|
parser = Psych::Parser.new
|
||||||
|
emitter = Psych::Emitter.new(nil)
|
||||||
|
assert_raise(Ractor::Error) { Ractor.make_shareable(parser) }
|
||||||
|
assert_raise(Ractor::Error) { Ractor.make_shareable(emitter) }
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ractor_config
|
||||||
|
assert_ractor(<<~RUBY, require_relative: 'helper')
|
||||||
|
r = Ractor.new do
|
||||||
|
Psych.add_builtin_type 'omap' do |type, val|
|
||||||
|
val * 2
|
||||||
|
end
|
||||||
|
Psych.load('--- !!omap hello')
|
||||||
|
end.take
|
||||||
|
assert_equal 'hellohello', r
|
||||||
|
assert_equal 'hello', Psych.load('--- !!omap hello')
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ractor_constants
|
||||||
|
assert_ractor(<<~RUBY, require_relative: 'helper')
|
||||||
|
r = Ractor.new do
|
||||||
|
Psych.libyaml_version.join('.') == Psych::LIBYAML_VERSION
|
||||||
|
end.take
|
||||||
|
assert_equal true, r
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue