Skip to content

Commit

Permalink
Make sure user seeding does not affect actor ID generation. (ray-proj…
Browse files Browse the repository at this point in the history
…ect#506)

* Make sure user seeding does not affect actor ID generation.

* Fix linting.

* Add test.
  • Loading branch information
robertnishihara authored and pcmoritz committed May 3, 2017
1 parent e50a23b commit 245c8ab
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 14 deletions.
7 changes: 1 addition & 6 deletions python/ray/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import hashlib
import inspect
import json
import numpy as np
import random
import redis
import traceback
Expand All @@ -14,7 +13,7 @@
import ray.pickling as pickling
import ray.signature as signature
import ray.worker
from ray.utils import binary_to_hex, hex_to_binary
from ray.utils import random_string, binary_to_hex, hex_to_binary

# This is a variable used by each actor to indicate the IDs of the GPUs that
# the worker is currently allowed to use.
Expand All @@ -30,10 +29,6 @@ def get_gpu_ids():
return gpu_ids


def random_string():
return np.random.bytes(20)


def random_actor_id():
return ray.local_scheduler.ObjectID(random_string())

Expand Down
26 changes: 26 additions & 0 deletions python/ray/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,37 @@
from __future__ import print_function

import binascii
import numpy as np
import sys

import ray.local_scheduler


def random_string():
"""Generate a random string to use as an ID.
Note that users may seed numpy, which could cause this function to generate
duplicate IDs. Therefore, we need to seed numpy ourselves, but we can't
interfere with the state of the user's random number generator, so we extract
the state of the random number generator and reset it after we are done.
TODO(rkn): If we want to later guarantee that these are generated in a
deterministic manner, then we will need to make some changes here.
Returns:
A random byte string of length 20.
"""
# Get the state of the numpy random number generator.
numpy_state = np.random.get_state()
# Try to use true randomness.
np.random.seed(None)
# Generate the random ID.
random_id = np.random.bytes(20)
# Reset the state of the numpy random number generator.
np.random.set_state(numpy_state)
return random_id


def decode(byte_str):
"""Make this unicode in Python 3, otherwise leave it as bytes."""
if sys.version_info >= (3, 0):
Expand Down
9 changes: 1 addition & 8 deletions python/ray/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import ray.numbuf
import ray.local_scheduler
import ray.plasma
from ray.utils import random_string

SCRIPT_MODE = 0
WORKER_MODE = 1
Expand Down Expand Up @@ -60,14 +61,6 @@
TASK_STATUS_RUNNING = 8


def random_string():
return np.random.bytes(20)


def random_object_id():
return ray.local_scheduler.ObjectID(random_string())


class FunctionID(object):
def __init__(self, function_id):
self.function_id = function_id
Expand Down
22 changes: 22 additions & 0 deletions test/actor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import print_function

import numpy as np
import random
import unittest

import ray
Expand Down Expand Up @@ -209,6 +210,27 @@ def __init__(self):

ray.worker.cleanup()

def testRandomIDGeneration(self):
ray.init(num_workers=0)

@ray.actor
class Foo(object):
def __init__(self):
pass

# Make sure that seeding numpy does not interfere with the generation of
# actor IDs.
np.random.seed(1234)
random.seed(1234)
f1 = Foo()
np.random.seed(1234)
random.seed(1234)
f2 = Foo()

self.assertNotEqual(f1._ray_actor_id.id(), f2._ray_actor_id.id())

ray.worker.cleanup()


class ActorMethods(unittest.TestCase):

Expand Down

0 comments on commit 245c8ab

Please sign in to comment.