Skip to content

per-ractor Random::DEFAULT #3813

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 27, 2020
Merged

per-ractor Random::DEFAULT #3813

merged 1 commit into from
Nov 27, 2020

Conversation

ko1
Copy link
Contributor

@ko1 ko1 commented Nov 25, 2020

Random generators are not Ractor-safe, so we need to prepare
per-ractor default random genearators. This patch set
Random::DEFAULT = Randm (not a Random instance, but the Random
class) and singleton methods like Random.rand() use a per-ractor
random generator.

@@ -829,7 +839,7 @@ static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_mt_t *r = &default_rand;
rb_random_mt_t *r = rand_mt_start(default_rand());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default_mt()?

Copy link
Member

@mrkn mrkn Nov 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we call rand_mt_start here, will rand_init be called twice?

Copy link
Contributor Author

@ko1 ko1 Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, the previous seed will be false (Qfalse) and srand() returns false if there is no usages of default_rand like rand() and so on.
If returning false by srand(), we can delete it.

Copy link
Member

@nobu nobu Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since rand_init() should initialize r->mt, genrand_initialized should be true and it will not be called again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default_rand allocates the memory of the default random object at the first srand call in each ractor.
Then random_mt_start calls rand_init for the default random object.
The second rand_init is called below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.
Seems OK to return 0 when old == Qfalse, instead of initialization here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll fix it.

static VALUE
random_s_seed(VALUE obj)
{
rb_random_mt_t *rnd = rand_mt_start(default_rand());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Copy link
Contributor Author

@ko1 ko1 Nov 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  def test_default_seed
    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
    begin;
      seed = Random::DEFAULT::seed
      rand1 = Random::DEFAULT::rand
      rand2 = Random.new(seed).rand
      assert_equal(rand1, rand2)

      srand seed
      rand3 = rand
      assert_equal(rand1, rand3)
    end;
  end

This test doesn't work...

Comment on lines +4 to +18

ruby_version_is ''...'3.0' do
it "returns a Random instance" do
Random::DEFAULT.should be_an_instance_of(Random)
end
end

ruby_version_is '3.0' do
it "returns a Random instance" do
Random::DEFAULT.should be_an_instance_of(Class)
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ruby_version_is ''...'3.0' do
it "returns a Random instance" do
Random::DEFAULT.should be_an_instance_of(Random)
end
end
ruby_version_is '3.0' do
it "returns a Random instance" do
Random::DEFAULT.should be_an_instance_of(Class)
end
it "returns a random number generator" do
Random::DEFAULT.should respond_to(:rand)
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems nice, but OTOH the current diff has the advantage that other Ruby implementations will notice the change and that they need to change what Random::DEFAULT points it when updating to Ruby 3.
Maybe have both?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be anything which generates (pseudo) random numbers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, both.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't feel reasonable that "the PRNG should be a class", but rather nonsense.
"It should respond to rand" would be fine as duck-typing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an implementation detail which is useless to be shared.
In fact, the constant might be a proxy object, and could be changed.
What we consider is just that "it works as a RNG".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Till now, no code uses that "Random::DEFAULT equals Random", of course.
If we publish this statement, users may write such code and we (including other implementors) will have to accept it.
If we don't, we can reject such code.
This is chicken-and-egg.

Copy link
Member

@eregon eregon Nov 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because Random::DEFAULT is Random will be in 3.0, users might depend on it. It would be nicer if they don't , but they might and there is nothing we can do about it, except if we deprecate the Random::DEFAULT constant.
The fact there is a test in ruby/spec doesn't mean some code is supported, recommended or anything. It just tries to test the behavior, in as much details as possible to improve compatibility between Ruby implementations.
Probably lots of tests in ruby/spec are not what user code should do, but they are useful tests nevertheless.

BTW, I think we should mention this change in NEWS because it could cause some incompatibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact there is a test in ruby/spec doesn't mean some code is supported, recommended or anything. It just tries to test the behavior, in as much details as possible to improve compatibility between Ruby implementations.
Probably lots of tests in ruby/spec are not what user code should do, but they are useful tests nevertheless.

Probably I've misunderstood your intention, ruby/spec is only for other implementors, but the other users should not rely on it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I forgot to reply to this.
I think ruby/spec is primarily for Ruby implementors yes, similar to the CRuby test suite.
I don't think many Ruby users look at ruby/spec, although of course they enjoy better-tested Ruby implementations.

Random generators are not Ractor-safe, so we need to prepare
per-ractor default random genearators. This patch set
`Random::DEFAULT = Randm` (not a Random instance, but the Random
class) and singleton methods like `Random.rand()` use a per-ractor
random generator.

[Feature #17322]
@ko1 ko1 merged commit 2db2fb9 into ruby:master Nov 27, 2020
@ko1 ko1 deleted the PerRactorRandom branch November 27, 2020 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy