mirror of
https://github.com/wassname/ray.git
synced 2026-07-12 18:32:07 +08:00
Implement named actors using the GCS service (#8328)
This commit is contained in:
@@ -17,7 +17,7 @@ from ray.includes.common cimport (
|
||||
CBuffer,
|
||||
CRayObject
|
||||
)
|
||||
from ray.includes.libcoreworker cimport CFiberEvent
|
||||
from ray.includes.libcoreworker cimport CActorHandle, CFiberEvent
|
||||
from ray.includes.unique_ids cimport (
|
||||
CObjectID,
|
||||
CActorID
|
||||
@@ -86,6 +86,7 @@ cdef class CoreWorker:
|
||||
self, worker, outputs, const c_vector[CObjectID] return_ids,
|
||||
c_vector[shared_ptr[CRayObject]] *returns)
|
||||
cdef yield_current_fiber(self, CFiberEvent &fiber_event)
|
||||
cdef make_actor_handle(self, CActorHandle *c_actor_handle)
|
||||
|
||||
cdef class FunctionDescriptor:
|
||||
cdef:
|
||||
|
||||
+37
-15
@@ -112,6 +112,12 @@ include "includes/libcoreworker.pxi"
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def gcs_actor_service_enabled():
|
||||
return (
|
||||
RayConfig.instance().gcs_service_enabled() and
|
||||
RayConfig.instance().gcs_actor_service_enabled())
|
||||
|
||||
|
||||
cdef int check_status(const CRayStatus& status) nogil except -1:
|
||||
if status.ok():
|
||||
return 0
|
||||
@@ -125,6 +131,8 @@ cdef int check_status(const CRayStatus& status) nogil except -1:
|
||||
raise KeyboardInterrupt()
|
||||
elif status.IsTimedOut():
|
||||
raise RayTimeoutError(message)
|
||||
elif status.IsNotFound():
|
||||
raise ValueError(message)
|
||||
else:
|
||||
raise RayletError(message)
|
||||
|
||||
@@ -899,6 +907,7 @@ cdef class CoreWorker:
|
||||
placement_resources,
|
||||
int32_t max_concurrency,
|
||||
c_bool is_detached,
|
||||
c_string name,
|
||||
c_bool is_asyncio,
|
||||
c_string extension_data):
|
||||
cdef:
|
||||
@@ -922,7 +931,7 @@ cdef class CoreWorker:
|
||||
CActorCreationOptions(
|
||||
max_reconstructions, max_concurrency,
|
||||
c_resources, c_placement_resources,
|
||||
dynamic_worker_options, is_detached, is_asyncio),
|
||||
dynamic_worker_options, is_detached, name, is_asyncio),
|
||||
extension_data,
|
||||
&c_actor_id))
|
||||
|
||||
@@ -1013,23 +1022,12 @@ cdef class CoreWorker:
|
||||
CCoreWorkerProcess.GetCoreWorker().RemoveActorHandleReference(
|
||||
c_actor_id)
|
||||
|
||||
def deserialize_and_register_actor_handle(self, const c_string &bytes,
|
||||
ObjectID
|
||||
outer_object_id):
|
||||
cdef:
|
||||
CActorHandle* c_actor_handle
|
||||
CObjectID c_outer_object_id = (outer_object_id.native() if
|
||||
outer_object_id else
|
||||
CObjectID.Nil())
|
||||
cdef make_actor_handle(self, CActorHandle *c_actor_handle):
|
||||
worker = ray.worker.global_worker
|
||||
worker.check_connected()
|
||||
manager = worker.function_actor_manager
|
||||
c_actor_id = (CCoreWorkerProcess.GetCoreWorker()
|
||||
.DeserializeAndRegisterActorHandle(
|
||||
bytes, c_outer_object_id))
|
||||
check_status(CCoreWorkerProcess.GetCoreWorker().GetActorHandle(
|
||||
c_actor_id, &c_actor_handle))
|
||||
actor_id = ActorID(c_actor_id.Binary())
|
||||
|
||||
actor_id = ActorID(c_actor_handle.GetActorID().Binary())
|
||||
job_id = JobID(c_actor_handle.CreationJobID().Binary())
|
||||
language = Language.from_native(c_actor_handle.ActorLanguage())
|
||||
actor_creation_function_descriptor = \
|
||||
@@ -1064,6 +1062,30 @@ cdef class CoreWorker:
|
||||
actor_creation_function_descriptor,
|
||||
worker.current_session_and_job)
|
||||
|
||||
def deserialize_and_register_actor_handle(self, const c_string &bytes,
|
||||
ObjectID
|
||||
outer_object_id):
|
||||
cdef:
|
||||
CActorHandle* c_actor_handle
|
||||
CObjectID c_outer_object_id = (outer_object_id.native() if
|
||||
outer_object_id else
|
||||
CObjectID.Nil())
|
||||
c_actor_id = (CCoreWorkerProcess.GetCoreWorker()
|
||||
.DeserializeAndRegisterActorHandle(
|
||||
bytes, c_outer_object_id))
|
||||
check_status(CCoreWorkerProcess.GetCoreWorker().GetActorHandle(
|
||||
c_actor_id, &c_actor_handle))
|
||||
return self.make_actor_handle(c_actor_handle)
|
||||
|
||||
def get_named_actor_handle(self, const c_string &name):
|
||||
cdef:
|
||||
CActorHandle* c_actor_handle
|
||||
|
||||
with nogil:
|
||||
check_status(CCoreWorkerProcess.GetCoreWorker()
|
||||
.GetNamedActorHandle(name, &c_actor_handle))
|
||||
return self.make_actor_handle(c_actor_handle)
|
||||
|
||||
def serialize_actor_handle(self, ActorID actor_id):
|
||||
cdef:
|
||||
c_string output
|
||||
|
||||
+16
-3
@@ -10,7 +10,7 @@ import ray._raylet
|
||||
import ray.signature as signature
|
||||
import ray.worker
|
||||
from ray import ActorClassID, Language
|
||||
from ray._raylet import PythonFunctionDescriptor
|
||||
from ray._raylet import PythonFunctionDescriptor, gcs_actor_service_enabled
|
||||
from ray import cross_language
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -472,11 +472,23 @@ class ActorClass:
|
||||
"Please use Actor._remote(name='some_name') "
|
||||
"to associate the name.")
|
||||
|
||||
if name and not detached:
|
||||
raise ValueError("Only detached actors can be named. "
|
||||
"Please use Actor._remote(detached=True, "
|
||||
"name='some_name').")
|
||||
|
||||
if name == "":
|
||||
raise ValueError("Actor name cannot be an empty string.")
|
||||
|
||||
# Check whether the name is already taken.
|
||||
# TODO(edoakes): this check has a race condition because two drivers
|
||||
# could pass the check and then create the same named actor. We should
|
||||
# instead check this when we create the actor, but that's currently an
|
||||
# async call.
|
||||
if name is not None:
|
||||
try:
|
||||
ray.util.get_actor(name)
|
||||
except ValueError: # name is not taken, expected.
|
||||
except ValueError: # Name is not taken.
|
||||
pass
|
||||
else:
|
||||
raise ValueError(
|
||||
@@ -551,6 +563,7 @@ class ActorClass:
|
||||
actor_placement_resources,
|
||||
max_concurrency,
|
||||
detached,
|
||||
name if name is not None else "",
|
||||
is_asyncio,
|
||||
# Store actor_method_cpu in actor handle's extension data.
|
||||
extension_data=str(actor_method_cpu))
|
||||
@@ -566,7 +579,7 @@ class ActorClass:
|
||||
worker.current_session_and_job,
|
||||
original_handle=True)
|
||||
|
||||
if name is not None:
|
||||
if name is not None and not gcs_actor_service_enabled():
|
||||
ray.util.register_actor(name, actor_handle)
|
||||
|
||||
return actor_handle
|
||||
|
||||
@@ -88,6 +88,9 @@ cdef extern from "ray/common/status.h" namespace "ray" nogil:
|
||||
@staticmethod
|
||||
CRayStatus UnexpectedSystemExit()
|
||||
|
||||
@staticmethod
|
||||
CRayStatus NotFound()
|
||||
|
||||
c_bool ok()
|
||||
c_bool IsOutOfMemory()
|
||||
c_bool IsKeyError()
|
||||
@@ -101,6 +104,7 @@ cdef extern from "ray/common/status.h" namespace "ray" nogil:
|
||||
c_bool IsTimedOut()
|
||||
c_bool IsInterrupted()
|
||||
c_bool IsSystemExit()
|
||||
c_bool IsNotFound()
|
||||
|
||||
c_string ToString()
|
||||
c_string CodeAsString()
|
||||
@@ -231,7 +235,7 @@ cdef extern from "ray/core_worker/common.h" nogil:
|
||||
const unordered_map[c_string, double] &resources,
|
||||
const unordered_map[c_string, double] &placement_resources,
|
||||
const c_vector[c_string] &dynamic_worker_options,
|
||||
c_bool is_detached, c_bool is_asyncio)
|
||||
c_bool is_detached, c_string &name, c_bool is_asyncio)
|
||||
|
||||
cdef extern from "ray/gcs/gcs_client.h" nogil:
|
||||
cdef cppclass CGcsClientOptions "ray::gcs::GcsClientOptions":
|
||||
|
||||
@@ -123,6 +123,8 @@ cdef extern from "ray/core_worker/core_worker.h" nogil:
|
||||
CObjectID *c_actor_handle_id)
|
||||
CRayStatus GetActorHandle(const CActorID &actor_id,
|
||||
CActorHandle **actor_handle) const
|
||||
CRayStatus GetNamedActorHandle(const c_string &name,
|
||||
CActorHandle **actor_handle)
|
||||
void AddLocalReference(const CObjectID &object_id)
|
||||
void RemoveLocalReference(const CObjectID &object_id)
|
||||
void PromoteObjectToPlasma(const CObjectID &object_id)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from libcpp cimport bool as c_bool
|
||||
from libc.stdint cimport int64_t, uint64_t, uint32_t
|
||||
from libcpp.string cimport string as c_string
|
||||
from libcpp.unordered_map cimport unordered_map
|
||||
@@ -83,3 +84,7 @@ cdef extern from "ray/common/ray_config.h" nogil:
|
||||
uint32_t maximum_gcs_deletion_batch_size() const
|
||||
|
||||
int64_t max_direct_call_object_size() const
|
||||
|
||||
c_bool gcs_service_enabled() const
|
||||
|
||||
c_bool gcs_actor_service_enabled() const
|
||||
|
||||
@@ -658,20 +658,31 @@ def test_detached_actor(ray_start_regular):
|
||||
def ping(self):
|
||||
return "pong"
|
||||
|
||||
with pytest.raises(Exception, match="Detached actors must be named"):
|
||||
with pytest.raises(
|
||||
ValueError, match="Actor name cannot be an empty string"):
|
||||
DetachedActor._remote(detached=True, name="")
|
||||
|
||||
with pytest.raises(ValueError, match="Detached actors must be named"):
|
||||
DetachedActor._remote(detached=True)
|
||||
|
||||
with pytest.raises(ValueError, match="Please use a different name"):
|
||||
_ = DetachedActor._remote(name="d_actor")
|
||||
with pytest.raises(ValueError, match="Only detached actors can be named"):
|
||||
DetachedActor._remote(name="d_actor")
|
||||
|
||||
DetachedActor._remote(detached=True, name="d_actor")
|
||||
with pytest.raises(ValueError, match="Please use a different name"):
|
||||
DetachedActor._remote(detached=True, name="d_actor")
|
||||
|
||||
redis_address = ray_start_regular["redis_address"]
|
||||
|
||||
actor_name = "DetachedActor"
|
||||
get_actor_name = "d_actor"
|
||||
create_actor_name = "DetachedActor"
|
||||
driver_script = """
|
||||
import ray
|
||||
ray.init(address="{}")
|
||||
|
||||
existing_actor = ray.util.get_actor("{}")
|
||||
assert ray.get(existing_actor.ping.remote()) == "pong"
|
||||
|
||||
@ray.remote
|
||||
class DetachedActor:
|
||||
def ping(self):
|
||||
@@ -679,10 +690,10 @@ class DetachedActor:
|
||||
|
||||
actor = DetachedActor._remote(name="{}", detached=True)
|
||||
ray.get(actor.ping.remote())
|
||||
""".format(redis_address, actor_name)
|
||||
""".format(redis_address, get_actor_name, create_actor_name)
|
||||
|
||||
run_string_as_driver(driver_script)
|
||||
detached_actor = ray.util.get_actor(actor_name)
|
||||
detached_actor = ray.util.get_actor(create_actor_name)
|
||||
assert ray.get(detached_actor.ping.remote()) == "pong"
|
||||
|
||||
|
||||
|
||||
@@ -26,11 +26,17 @@ def get_actor(name):
|
||||
Returns:
|
||||
The ActorHandle object corresponding to the name.
|
||||
"""
|
||||
actor_name = _calculate_key(name)
|
||||
pickled_state = _internal_kv_get(actor_name)
|
||||
if pickled_state is None:
|
||||
raise ValueError("The actor with name={} doesn't exist".format(name))
|
||||
handle = pickle.loads(pickled_state)
|
||||
if ray._raylet.gcs_actor_service_enabled():
|
||||
worker = ray.worker.global_worker
|
||||
handle = worker.core_worker.get_named_actor_handle(name)
|
||||
else:
|
||||
actor_name = _calculate_key(name)
|
||||
pickled_state = _internal_kv_get(actor_name)
|
||||
if pickled_state is None:
|
||||
raise ValueError(
|
||||
"The actor with name={} doesn't exist".format(name))
|
||||
handle = pickle.loads(pickled_state)
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user