[前][次][番号順一覧][スレッド一覧]

ruby-changes:64511

From: Marc-Andre <ko1@a...>
Date: Wed, 23 Dec 2020 15:09:00 +0900 (JST)
Subject: [ruby-changes:64511] c5a445d577 (master): [ruby/psych] Make Ractor-ready.

https://git.ruby-lang.org/ruby.git/commit/?id=c5a445d577

From c5a445d577b786e31c420b5857ad05b954b420ec Mon Sep 17 00:00:00 2001
From: Marc-Andre Lafortune <github@m...>
Date: Sun, 20 Dec 2020 21:42:25 -0500
Subject: [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).

diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index 0b62362..cedf0a4 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -632,9 +632,29 @@ module Psych https://github.com/ruby/ruby/blob/trunk/ext/psych/lib/psych.rb#L632
   private_class_method :warn_with_uplevel, :parse_caller
 
   class << self
-    attr_accessor :load_tags
-    attr_accessor :dump_tags
-    attr_accessor :domain_types
+    if defined?(Ractor)
+      require 'forwardable'
+      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
   self.load_tags = {}
   self.dump_tags = {}
diff --git a/ext/psych/lib/psych/visitors/visitor.rb b/ext/psych/lib/psych/visitors/visitor.rb
index 3f4ba64..35f8f81 100644
--- a/ext/psych/lib/psych/visitors/visitor.rb
+++ b/ext/psych/lib/psych/visitors/visitor.rb
@@ -8,12 +8,26 @@ module Psych https://github.com/ruby/ruby/blob/trunk/ext/psych/lib/psych/visitors/visitor.rb#L8
 
       private
 
-      DISPATCH = Hash.new do |hash, klass|
-        hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
+      # @api private
+      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
 
       def visit target
-        send DISPATCH[target.class], target
+        send dispatch[target.class], target
       end
     end
   end
diff --git a/ext/psych/psych.c b/ext/psych/psych.c
index 0afd731..8af0bb6 100644
--- a/ext/psych/psych.c
+++ b/ext/psych/psych.c
@@ -22,6 +22,9 @@ VALUE mPsych; https://github.com/ruby/ruby/blob/trunk/ext/psych/psych.c#L22
 
 void Init_psych(void)
 {
+    #ifdef HAVE_RB_EXT_RACTOR_SAFE
+	RB_EXT_RACTOR_SAFE(true);
+    #endif
     mPsych = rb_define_module("Psych");
 
     rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0);
diff --git a/test/psych/test_ractor.rb b/test/psych/test_ractor.rb
new file mode 100644
index 0000000..90e4036
--- /dev/null
+++ b/test/psych/test_ractor.rb
@@ -0,0 +1,47 @@ https://github.com/ruby/ruby/blob/trunk/test/psych/test_ractor.rb#L1
+# 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
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]