xoscar 0.9.0__cp312-cp312-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. xoscar/__init__.py +61 -0
  2. xoscar/_utils.cpython-312-darwin.so +0 -0
  3. xoscar/_utils.pxd +36 -0
  4. xoscar/_utils.pyx +246 -0
  5. xoscar/_version.py +693 -0
  6. xoscar/aio/__init__.py +16 -0
  7. xoscar/aio/base.py +86 -0
  8. xoscar/aio/file.py +59 -0
  9. xoscar/aio/lru.py +228 -0
  10. xoscar/aio/parallelism.py +39 -0
  11. xoscar/api.py +527 -0
  12. xoscar/backend.py +67 -0
  13. xoscar/backends/__init__.py +14 -0
  14. xoscar/backends/allocate_strategy.py +160 -0
  15. xoscar/backends/communication/__init__.py +30 -0
  16. xoscar/backends/communication/base.py +315 -0
  17. xoscar/backends/communication/core.py +69 -0
  18. xoscar/backends/communication/dummy.py +253 -0
  19. xoscar/backends/communication/errors.py +20 -0
  20. xoscar/backends/communication/socket.py +444 -0
  21. xoscar/backends/communication/ucx.py +538 -0
  22. xoscar/backends/communication/utils.py +97 -0
  23. xoscar/backends/config.py +157 -0
  24. xoscar/backends/context.py +437 -0
  25. xoscar/backends/core.py +352 -0
  26. xoscar/backends/indigen/__init__.py +16 -0
  27. xoscar/backends/indigen/__main__.py +19 -0
  28. xoscar/backends/indigen/backend.py +51 -0
  29. xoscar/backends/indigen/driver.py +26 -0
  30. xoscar/backends/indigen/fate_sharing.py +221 -0
  31. xoscar/backends/indigen/pool.py +515 -0
  32. xoscar/backends/indigen/shared_memory.py +548 -0
  33. xoscar/backends/message.cpython-312-darwin.so +0 -0
  34. xoscar/backends/message.pyi +255 -0
  35. xoscar/backends/message.pyx +646 -0
  36. xoscar/backends/pool.py +1630 -0
  37. xoscar/backends/router.py +285 -0
  38. xoscar/backends/test/__init__.py +16 -0
  39. xoscar/backends/test/backend.py +38 -0
  40. xoscar/backends/test/pool.py +233 -0
  41. xoscar/batch.py +256 -0
  42. xoscar/collective/__init__.py +27 -0
  43. xoscar/collective/backend/__init__.py +13 -0
  44. xoscar/collective/backend/nccl_backend.py +160 -0
  45. xoscar/collective/common.py +102 -0
  46. xoscar/collective/core.py +737 -0
  47. xoscar/collective/process_group.py +687 -0
  48. xoscar/collective/utils.py +41 -0
  49. xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
  50. xoscar/collective/xoscar_pygloo.pyi +239 -0
  51. xoscar/constants.py +23 -0
  52. xoscar/context.cpython-312-darwin.so +0 -0
  53. xoscar/context.pxd +21 -0
  54. xoscar/context.pyx +368 -0
  55. xoscar/core.cpython-312-darwin.so +0 -0
  56. xoscar/core.pxd +51 -0
  57. xoscar/core.pyx +664 -0
  58. xoscar/debug.py +188 -0
  59. xoscar/driver.py +42 -0
  60. xoscar/errors.py +63 -0
  61. xoscar/libcpp.pxd +31 -0
  62. xoscar/metrics/__init__.py +21 -0
  63. xoscar/metrics/api.py +288 -0
  64. xoscar/metrics/backends/__init__.py +13 -0
  65. xoscar/metrics/backends/console/__init__.py +13 -0
  66. xoscar/metrics/backends/console/console_metric.py +82 -0
  67. xoscar/metrics/backends/metric.py +149 -0
  68. xoscar/metrics/backends/prometheus/__init__.py +13 -0
  69. xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
  70. xoscar/nvutils.py +717 -0
  71. xoscar/profiling.py +260 -0
  72. xoscar/serialization/__init__.py +20 -0
  73. xoscar/serialization/aio.py +141 -0
  74. xoscar/serialization/core.cpython-312-darwin.so +0 -0
  75. xoscar/serialization/core.pxd +28 -0
  76. xoscar/serialization/core.pyi +57 -0
  77. xoscar/serialization/core.pyx +944 -0
  78. xoscar/serialization/cuda.py +111 -0
  79. xoscar/serialization/exception.py +48 -0
  80. xoscar/serialization/mlx.py +67 -0
  81. xoscar/serialization/numpy.py +82 -0
  82. xoscar/serialization/pyfury.py +37 -0
  83. xoscar/serialization/scipy.py +72 -0
  84. xoscar/serialization/torch.py +180 -0
  85. xoscar/utils.py +522 -0
  86. xoscar/virtualenv/__init__.py +34 -0
  87. xoscar/virtualenv/core.py +268 -0
  88. xoscar/virtualenv/platform.py +56 -0
  89. xoscar/virtualenv/utils.py +100 -0
  90. xoscar/virtualenv/uv.py +321 -0
  91. xoscar-0.9.0.dist-info/METADATA +230 -0
  92. xoscar-0.9.0.dist-info/RECORD +94 -0
  93. xoscar-0.9.0.dist-info/WHEEL +6 -0
  94. xoscar-0.9.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,41 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import os
15
+
16
+ import numpy as np
17
+
18
+ from ..utils import lazy_import
19
+
20
+ cupy = lazy_import("cupy")
21
+
22
+
23
+ def convert_data_to_np_array(data):
24
+ if isinstance(data, np.ndarray):
25
+ return data
26
+ else:
27
+ return np.frombuffer(data, dtype="u1")
28
+
29
+
30
+ def convert_data_to_cp_array(data):
31
+ if isinstance(data, cupy.ndarray):
32
+ return data
33
+ else:
34
+ return cupy.frombuffer(data, dtype="u1")
35
+
36
+
37
+ def get_rank_address_via_env(env_key: str, err_message: str) -> str:
38
+ address = os.environ.get(env_key, None)
39
+ if address is None:
40
+ raise RuntimeError(err_message)
41
+ return address
@@ -0,0 +1,239 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import datetime
16
+ from ctypes import c_void_p
17
+ from enum import IntEnum
18
+ from typing import Callable, List, Optional
19
+
20
+ import xoscar_pygloo
21
+
22
+ class ReduceOp(IntEnum):
23
+ SUM = 0
24
+ PRODUCT = 1
25
+ MIN = 2
26
+ MAX = 3
27
+ BAND = 4
28
+ BOR = 5
29
+ BXOR = 6
30
+ UNUSED = 7
31
+
32
+ class GlooDataType_t(IntEnum):
33
+ glooInt8 = 0
34
+ glooUint8 = 1
35
+ glooInt32 = 2
36
+ glooUint32 = 3
37
+ glooInt64 = 4
38
+ glooUint64 = 5
39
+ glooFloat16 = 6
40
+ glooFloat32 = 7
41
+ glooFloat64 = 8
42
+
43
+ class AllreduceAlgorithm(IntEnum):
44
+ UNSPECIFIED = 0
45
+ RING = 1
46
+ BCUBE = 2
47
+
48
+ def transport_tcp_available() -> bool: ...
49
+ def transport_uv_available() -> bool: ...
50
+
51
+ class Context:
52
+ rank: Optional[int] = None
53
+ size: Optional[int] = None
54
+ base: Optional[int] = 2
55
+ def getDevice(self) -> int: ...
56
+ def createUnboundBuffer(self, ptr: c_void_p, size: int): ...
57
+ def nextSlot(self, numToSkip: int) -> int: ...
58
+ def closeConnections(self) -> None: ...
59
+ def setTimeout(self, timeout: datetime.timedelta) -> None: ...
60
+ def getTimeout(self) -> datetime.timedelta: ...
61
+
62
+ def allreduce(
63
+ context: Optional[Context] = None,
64
+ sendbuf: Optional[int] = None,
65
+ recvbuf: Optional[int] = None,
66
+ size: Optional[int] = None,
67
+ datatype: Optional[GlooDataType_t] = None,
68
+ reduceop: Optional[ReduceOp] = ReduceOp.SUM,
69
+ algorithm: Optional[AllreduceAlgorithm] = AllreduceAlgorithm.RING,
70
+ tag: int = 0,
71
+ ) -> None: ...
72
+ def allgather(
73
+ context: Optional[Context] = None,
74
+ sendbuf: Optional[int] = None,
75
+ recvbuf: Optional[int] = None,
76
+ size: Optional[int] = None,
77
+ datatype: Optional[GlooDataType_t] = None,
78
+ tag: Optional[int] = 0,
79
+ ) -> None: ...
80
+ def all_to_all(
81
+ context: Optional[Context] = None,
82
+ sendbuf: Optional[int] = None,
83
+ recvbuf: Optional[int] = None,
84
+ size: Optional[int] = None,
85
+ datatype: Optional[GlooDataType_t] = None,
86
+ tag: Optional[int] = 0,
87
+ ) -> None: ...
88
+ def allgatherv(
89
+ context: Optional[Context] = None,
90
+ sendbuf: Optional[int] = None,
91
+ recvbuf: Optional[int] = None,
92
+ size: Optional[int] = None,
93
+ datatype: Optional[GlooDataType_t] = None,
94
+ tag: Optional[int] = 0,
95
+ ) -> None: ...
96
+ def reduce(
97
+ context: Optional[Context] = None,
98
+ sendbuf: Optional[int] = None,
99
+ recvbuf: Optional[int] = None,
100
+ size: Optional[int] = None,
101
+ datatype: Optional[GlooDataType_t] = None,
102
+ reduceop: Optional[ReduceOp] = ReduceOp.SUM,
103
+ root: Optional[int] = 0,
104
+ tag: Optional[int] = 0,
105
+ ) -> None: ...
106
+ def scatter(
107
+ context: Optional[Context] = None,
108
+ sendbuf: Optional[int] = None,
109
+ recvbuf: Optional[int] = None,
110
+ size: Optional[int] = None,
111
+ datatype: Optional[GlooDataType_t] = None,
112
+ root: Optional[int] = 0,
113
+ tag: Optional[int] = 0,
114
+ ) -> None: ...
115
+ def gather(
116
+ context: Optional[Context] = None,
117
+ sendbuf: Optional[int] = None,
118
+ recvbuf: Optional[int] = None,
119
+ size: Optional[int] = None,
120
+ datatype: Optional[GlooDataType_t] = None,
121
+ root: Optional[int] = 0,
122
+ tag: Optional[int] = 0,
123
+ ) -> None: ...
124
+ def send(
125
+ context: Optional[Context] = None,
126
+ sendbuf: Optional[int] = None,
127
+ size: Optional[int] = None,
128
+ datatype: Optional[GlooDataType_t] = None,
129
+ peer: Optional[int] = None,
130
+ tag: Optional[int] = 0,
131
+ ) -> None: ...
132
+ def recv(
133
+ context: Optional[Context] = None,
134
+ recvbuf: Optional[int] = None,
135
+ size: Optional[int] = None,
136
+ datatype: Optional[GlooDataType_t] = None,
137
+ peer: Optional[int] = None,
138
+ tag: Optional[int] = 0,
139
+ ) -> None: ...
140
+ def broadcast(
141
+ context: Optional[Context] = None,
142
+ sendbuf: Optional[int] = None,
143
+ recvbuf: Optional[int] = None,
144
+ size: Optional[int] = None,
145
+ datatype: Optional[GlooDataType_t] = None,
146
+ root: Optional[int] = 0,
147
+ tag: Optional[int] = 0,
148
+ ) -> None: ...
149
+ def reduce_scatter(
150
+ context: Optional[Context] = None,
151
+ sendbuf: Optional[int] = None,
152
+ recvbuf: Optional[int] = None,
153
+ size: Optional[int] = None,
154
+ recvElems: Optional[List[int]] = None,
155
+ datatype: Optional[GlooDataType_t] = None,
156
+ reduceop: Optional[ReduceOp] = ReduceOp.SUM,
157
+ ) -> None: ...
158
+ def barrier(context: Optional[Context] = None, tag: Optional[int] = 0) -> None: ...
159
+
160
+ class rendezvous:
161
+ class Store:
162
+ def set(self, key: str, data: List[str]) -> None: ...
163
+ def get(self, key: str) -> str: ...
164
+
165
+ class TCPStoreOptions:
166
+ port: int
167
+ isServer: bool
168
+ numWorkers: Optional[int]
169
+ waitWorkers: bool
170
+ timeout: datetime.timedelta
171
+ multiTenant: bool
172
+
173
+ class TCPStore:
174
+ def __init__(
175
+ self,
176
+ host: str,
177
+ opts: rendezvous.TCPStoreOptions = rendezvous.TCPStoreOptions(),
178
+ ): ...
179
+ def set(self, key: str, value: bytes): ...
180
+ def get(self, key: str) -> bytes: ...
181
+ def wait(self, keys: List[str]): ...
182
+
183
+ class FileStore(Store):
184
+ def __init__(self, path: str) -> None: ...
185
+ def set(self, key: str, data: List[str]) -> None: ...
186
+ def get(self, key: str) -> str: ...
187
+
188
+ class HashStore(Store):
189
+ def __init__(self) -> None: ...
190
+ def set(self, key: str, data: List[str]) -> None: ...
191
+ def get(self, key: str) -> str: ...
192
+
193
+ class PrefixStore(Store):
194
+ def __init__(self, prefix: str, store: rendezvous.Store) -> None: ...
195
+ def set(self, key: str, data: List[str]) -> None: ...
196
+ def get(self, key: str) -> str: ...
197
+
198
+ class CustomStore(Store):
199
+ def __init__(self, real_store_py_object: object) -> None: ...
200
+ def delKeys(self, keys: List[str]) -> None: ...
201
+ def set(self, key: str, data: List[str]) -> None: ...
202
+ def get(self, key: str) -> str: ...
203
+
204
+ class Context(xoscar_pygloo.Context):
205
+ def connectFullMesh(
206
+ self, store: rendezvous.Store, dev: transport.Device
207
+ ) -> None: ...
208
+
209
+ class transport:
210
+ class uv:
211
+ pass
212
+
213
+ class tcp:
214
+ class Device(transport.Device):
215
+ def __init__(self, attr: transport.tcp.attr) -> None: ...
216
+
217
+ class Context(xoscar_pygloo.Context):
218
+ def __init__(
219
+ self, device: transport.tcp.Device, rank: int, size: int
220
+ ) -> None: ...
221
+
222
+ class attr:
223
+ hostname: str
224
+ iface: str
225
+ ai_family: int
226
+ ai_socktype: int
227
+ ai_protocol: int
228
+ ai_addr: object
229
+ ai_addrlen: int
230
+ def __init__(self, string: Optional[str] = None) -> None: ...
231
+
232
+ def CreateDevice(self, src: transport.tcp.attr) -> transport.Device: ...
233
+
234
+ class Device:
235
+ def __str__(self) -> str: ...
236
+ def getPCIBusID(self) -> Callable[[], str]: ...
237
+ def getInterfaceSpeed(self) -> int: ...
238
+ def hasGPUDirect(self) -> bool: ...
239
+ def createContext(self, rank: int, size: int): ...
xoscar/constants.py ADDED
@@ -0,0 +1,23 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import os
16
+ from pathlib import Path
17
+
18
+ XOSCAR_TEMP_DIR = Path(os.getenv("XOSCAR_DIR", Path.home())) / ".xoscar"
19
+
20
+ # unix socket.
21
+ XOSCAR_UNIX_SOCKET_DIR = XOSCAR_TEMP_DIR / "socket"
22
+
23
+ XOSCAR_CONNECT_TIMEOUT = 8
Binary file
xoscar/context.pxd ADDED
@@ -0,0 +1,21 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ cdef class BaseActorContext:
18
+ cdef public str _address
19
+
20
+
21
+ cpdef get_context()
xoscar/context.pyx ADDED
@@ -0,0 +1,368 @@
1
+ # Copyright 2022-2023 XProbe Inc.
2
+ # derived from copyright 1999-2021 Alibaba Group Holding Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ from typing import Any, List, Optional, Union
16
+ from urllib.parse import urlparse
17
+
18
+ from ._utils cimport new_actor_id, new_random_id
19
+ from .core cimport ActorRef, BufferRef, FileObjectRef
20
+
21
+
22
+ cdef dict _backend_context_cls = dict()
23
+
24
+ cdef object _context = None
25
+
26
+
27
+ cdef class BaseActorContext:
28
+ # allocate strategy is for Indigen backend only
29
+ support_allocate_strategy = False
30
+
31
+ """
32
+ Base class for actor context. Every backend need to implement
33
+ actor context for their own.
34
+ """
35
+
36
+ def __init__(self, address: str = None):
37
+ self._address = address
38
+
39
+ async def create_actor(
40
+ self,
41
+ object actor_cls,
42
+ *args,
43
+ object uid=None,
44
+ object address=None,
45
+ **kwargs,
46
+ ):
47
+ """
48
+ Stub method for creating an actor in current context.
49
+
50
+ Parameters
51
+ ----------
52
+ actor_cls : Actor
53
+ Actor class
54
+ args : tuple
55
+ args to be passed into actor_cls.__init__
56
+ uid : identifier
57
+ Actor identifier
58
+ address : str
59
+ Address to locate the actor
60
+ kwargs : dict
61
+ kwargs to be passed into actor_cls.__init__
62
+
63
+ Returns
64
+ -------
65
+ ActorRef
66
+
67
+ """
68
+ raise NotImplementedError
69
+
70
+ async def has_actor(self, ActorRef actor_ref):
71
+ """
72
+ Check if actor exists in current context
73
+
74
+ Parameters
75
+ ----------
76
+ actor_ref : ActorRef
77
+ Reference to an actor
78
+
79
+ Returns
80
+ -------
81
+ bool
82
+ """
83
+ raise NotImplementedError
84
+
85
+ async def destroy_actor(self, ActorRef actor_ref):
86
+ """
87
+ Destroy an actor by its reference
88
+
89
+ Parameters
90
+ ----------
91
+ actor_ref : ActorRef
92
+ Reference to an actor
93
+
94
+ Returns
95
+ -------
96
+ bool
97
+ """
98
+ raise NotImplementedError
99
+
100
+ async def kill_actor(self, ActorRef actor_ref):
101
+ """
102
+ Force to kill an actor, take care this is a dangerous operation,
103
+ it may lead to the result that other actors are killed as well.
104
+ Hence, unless you are knowing what you are doing and know how
105
+ to recover possible effected actors, DO NOT USE this method!
106
+
107
+ Parameters
108
+ ----------
109
+ actor_ref : ActorRef
110
+ Reference to an actor
111
+
112
+ Returns
113
+ -------
114
+ bool
115
+ """
116
+
117
+ async def send(
118
+ self,
119
+ ActorRef actor_ref,
120
+ object message,
121
+ bint wait_response=True,
122
+ object profiling_context=None,
123
+ ):
124
+ """
125
+ Send a message to given actor by its reference
126
+
127
+ Parameters
128
+ ----------
129
+ actor_ref : ActorRef
130
+ Reference to an actor
131
+ message : object
132
+ Message to send to an actor, need to comply to Actor.__on_receive__
133
+ wait_response : bool
134
+ Whether to wait for responses from the actor.
135
+ profiling_context: ProfilingContext
136
+ The profiling context.
137
+
138
+ Returns
139
+ -------
140
+ object
141
+ """
142
+ raise NotImplementedError
143
+
144
+ async def actor_ref(self, *args, **kwargs):
145
+ """
146
+ Create a reference to an actor
147
+
148
+ Returns
149
+ -------
150
+ ActorRef
151
+ """
152
+ raise NotImplementedError
153
+
154
+ async def wait_actor_pool_recovered(self, str address, str main_address = None):
155
+ """
156
+ Wait until an actor pool is recovered
157
+
158
+ Parameters
159
+ ----------
160
+ address
161
+ address of the actor pool
162
+ main_address
163
+ address of the main pool
164
+ """
165
+ raise NotImplementedError
166
+
167
+ async def get_pool_config(self, str address):
168
+ """
169
+ Get config of actor pool with given address
170
+
171
+ Parameters
172
+ ----------
173
+ address
174
+ address of the actor pool
175
+
176
+ Returns
177
+ -------
178
+
179
+ """
180
+ raise NotImplementedError
181
+
182
+ def buffer_ref(self, str address, object buf) -> BufferRef:
183
+ """
184
+ Create a reference to a buffer
185
+
186
+ Parameters
187
+ ----------
188
+ address
189
+ address of the actor pool
190
+ buf
191
+ buffer object
192
+
193
+ Returns
194
+ -------
195
+ BufferRef
196
+ """
197
+ return BufferRef.create(buf, address, new_random_id(32))
198
+
199
+ def file_object_ref(self, str address, object file_object) -> FileObjectRef:
200
+ """
201
+ Create a reference to an aio file object
202
+
203
+ Parameters
204
+ ----------
205
+ address
206
+ address of the actor pool
207
+ file_object
208
+ aio file object
209
+
210
+ Returns
211
+ -------
212
+ FileObjectRef
213
+ """
214
+ return FileObjectRef.create(file_object, address, new_random_id(32))
215
+
216
+ async def copy_to_buffers(self, local_buffers: List, remote_buffer_refs: List[BufferRef], block_size: Optional[int] = None):
217
+ """
218
+ Copy local buffers to remote buffers.
219
+ Parameters
220
+ ----------
221
+ local_buffers
222
+ Local buffers.
223
+ remote_buffer_refs
224
+ Remote buffer refs
225
+ block_size
226
+ Transfer block size when non-ucx
227
+ """
228
+ raise NotImplementedError
229
+
230
+ async def copy_to_fileobjs(self, local_fileobjs: list, remote_fileobj_refs: List[FileObjectRef], block_size: Optional[int] = None):
231
+ """
232
+ Copy local file objs to remote file objs.
233
+ Parameters
234
+ ----------
235
+ local_fileobjs
236
+ Local file objs.
237
+ remote_fileobj_refs
238
+ Remote file object refs
239
+ block_size
240
+ Transfer block size when non-ucx
241
+ """
242
+ raise NotImplementedError
243
+
244
+
245
+ cdef class ClientActorContext(BaseActorContext):
246
+ """
247
+ Default actor context. This context will keep references to other contexts
248
+ given their protocol scheme (i.e., `ray://xxx`).
249
+ """
250
+ cdef dict _backend_contexts
251
+
252
+ def __init__(self, address: str = None):
253
+ BaseActorContext.__init__(self, address)
254
+ self._backend_contexts = dict()
255
+
256
+ cdef inline object _get_backend_context(self, object address):
257
+ if address is None:
258
+ raise ValueError('address has to be provided')
259
+ if '://' not in address:
260
+ scheme = None
261
+ else:
262
+ scheme = urlparse(address).scheme or None
263
+ try:
264
+ return self._backend_contexts[scheme]
265
+ except KeyError:
266
+ context = self._backend_contexts[scheme] = \
267
+ _backend_context_cls[scheme](address)
268
+ return context
269
+
270
+ def create_actor(
271
+ self,
272
+ object actor_cls,
273
+ *args,
274
+ object uid=None,
275
+ object address=None,
276
+ **kwargs,
277
+ ):
278
+ context = self._get_backend_context(address)
279
+ uid = uid or new_actor_id()
280
+ return context.create_actor(actor_cls, *args, uid=uid, address=address, **kwargs)
281
+
282
+ def has_actor(self, ActorRef actor_ref):
283
+ context = self._get_backend_context(actor_ref.address)
284
+ return context.has_actor(actor_ref)
285
+
286
+ def destroy_actor(self, ActorRef actor_ref):
287
+ context = self._get_backend_context(actor_ref.address)
288
+ return context.destroy_actor(actor_ref)
289
+
290
+ def kill_actor(self, ActorRef actor_ref):
291
+ context = self._get_backend_context(actor_ref.address)
292
+ return context.kill_actor(actor_ref)
293
+
294
+ def actor_ref(self, *args, **kwargs):
295
+ from ._utils import create_actor_ref
296
+
297
+ actor_ref = create_actor_ref(*args, **kwargs)
298
+ context = self._get_backend_context(actor_ref.address)
299
+ return context.actor_ref(actor_ref)
300
+
301
+ def send(
302
+ self,
303
+ ActorRef actor_ref,
304
+ object message,
305
+ bint wait_response=True,
306
+ object profiling_context=None
307
+ ):
308
+ context = self._get_backend_context(actor_ref.address)
309
+ return context.send(
310
+ actor_ref,
311
+ message,
312
+ wait_response=wait_response,
313
+ profiling_context=profiling_context,
314
+ )
315
+
316
+ def wait_actor_pool_recovered(self, str address, str main_address = None):
317
+ context = self._get_backend_context(address)
318
+ return context.wait_actor_pool_recovered(address, main_address)
319
+
320
+ def get_pool_config(self, str address):
321
+ context = self._get_backend_context(address)
322
+ return context.get_pool_config(address)
323
+
324
+ def buffer_ref(self, str address, buf: Any) -> BufferRef:
325
+ context = self._get_backend_context(address)
326
+ return context.buffer_ref(address, buf)
327
+
328
+ def file_object_ref(self, str address, object file_object) -> FileObjectRef:
329
+ context = self._get_backend_context(address)
330
+ return context.file_object_ref(address, file_object)
331
+
332
+ def copy_to(self, local_buffers_or_fileobjs: list, remote_refs: List[Union[BufferRef, FileObjectRef]], block_size: Optional[int] = None):
333
+ if len(local_buffers_or_fileobjs) == 0 or len(remote_refs) == 0:
334
+ raise ValueError("Nothing to transfer since the length of `local_buffers_or_fileobjs` or `remote_refs` is 0.")
335
+ assert (
336
+ len({ref.address for ref in remote_refs}) == 1
337
+ ), "remote_refs for `copy_to` can support only 1 destination"
338
+ assert len(local_buffers_or_fileobjs) == len(remote_refs), (
339
+ f"Buffers or fileobjs from local and remote must have same size, "
340
+ f"local: {len(local_buffers_or_fileobjs)}, remote: {len(remote_refs)}"
341
+ )
342
+ if block_size is not None:
343
+ assert (
344
+ block_size > 0
345
+ ), f"`block_size` option must be greater than 0, current value: {block_size}."
346
+ remote_ref = remote_refs[0]
347
+ address = remote_ref.address
348
+ context = self._get_backend_context(address)
349
+ if isinstance(remote_ref, BufferRef):
350
+ return context.copy_to_buffers(local_buffers_or_fileobjs, remote_refs, block_size)
351
+ else:
352
+ return context.copy_to_fileobjs(local_buffers_or_fileobjs, remote_refs, block_size)
353
+
354
+
355
+ def register_backend_context(scheme, cls):
356
+ assert issubclass(cls, BaseActorContext)
357
+ _backend_context_cls[scheme] = cls
358
+
359
+
360
+ cpdef get_context():
361
+ """
362
+ Get an actor context. If not in an actor environment,
363
+ ClientActorContext will be used
364
+ """
365
+ global _context
366
+ if _context is None:
367
+ _context = ClientActorContext()
368
+ return _context
Binary file