xoscar 0.1.4__cp38-cp38-macosx_10_9_universal2.whl → 0.2.1__cp38-cp38-macosx_10_9_universal2.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.

Potentially problematic release.


This version of xoscar might be problematic. Click here for more details.

xoscar/__init__.py CHANGED
@@ -32,6 +32,7 @@ from .api import (
32
32
  setup_cluster,
33
33
  wait_actor_pool_recovered,
34
34
  get_pool_config,
35
+ generator,
35
36
  )
36
37
  from .backends import allocate_strategy
37
38
  from .backends.pool import MainActorPoolType
Binary file
xoscar/api.py CHANGED
@@ -15,9 +15,26 @@
15
15
 
16
16
  from __future__ import annotations
17
17
 
18
+ import asyncio
19
+ import functools
20
+ import inspect
21
+ import logging
22
+ import threading
23
+ import uuid
18
24
  from collections import defaultdict
19
25
  from numbers import Number
20
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union
26
+ from typing import (
27
+ TYPE_CHECKING,
28
+ Any,
29
+ Dict,
30
+ Generic,
31
+ List,
32
+ Optional,
33
+ Tuple,
34
+ Type,
35
+ TypeVar,
36
+ Union,
37
+ )
21
38
  from urllib.parse import urlparse
22
39
 
23
40
  from .aio import AioFileObject
@@ -29,6 +46,8 @@ if TYPE_CHECKING:
29
46
  from .backends.config import ActorPoolConfig
30
47
  from .backends.pool import MainActorPoolType
31
48
 
49
+ logger = logging.getLogger(__name__)
50
+
32
51
 
33
52
  async def create_actor(
34
53
  actor_cls: Type, *args, uid=None, address=None, **kwargs
@@ -271,6 +290,61 @@ def setup_cluster(address_to_resources: Dict[str, Dict[str, Number]]):
271
290
  get_backend(scheme).get_driver_cls().setup_cluster(address_resources)
272
291
 
273
292
 
293
+ T = TypeVar("T")
294
+
295
+
296
+ class IteratorWrapper(Generic[T]):
297
+ def __init__(self, uid: str, actor_addr: str, actor_uid: str):
298
+ self._uid = uid
299
+ self._actor_addr = actor_addr
300
+ self._actor_uid = actor_uid
301
+ self._actor_ref = None
302
+ self._gc_destroy = True
303
+
304
+ async def destroy(self):
305
+ if self._actor_ref is None:
306
+ self._actor_ref = await actor_ref(
307
+ address=self._actor_addr, uid=self._actor_uid
308
+ )
309
+ assert self._actor_ref is not None
310
+ return await self._actor_ref.__xoscar_destroy_generator__(self._uid)
311
+
312
+ def __del__(self):
313
+ # It's not a good idea to spawn a new thread and join in __del__,
314
+ # but currently it's the only way to GC the generator.
315
+ # TODO(codingl2k1): This __del__ may hangs if the program is exiting.
316
+ if self._gc_destroy:
317
+ thread = threading.Thread(
318
+ target=asyncio.run, args=(self.destroy(),), daemon=True
319
+ )
320
+ thread.start()
321
+ thread.join()
322
+
323
+ def __aiter__(self):
324
+ return self
325
+
326
+ def __getstate__(self):
327
+ # Transfer gc destroy during serialization.
328
+ state = self.__dict__.copy()
329
+ state["_gc_destroy"] = True
330
+ self._gc_destroy = False
331
+ return state
332
+
333
+ async def __anext__(self) -> T:
334
+ if self._actor_ref is None:
335
+ self._actor_ref = await actor_ref(
336
+ address=self._actor_addr, uid=self._actor_uid
337
+ )
338
+ try:
339
+ assert self._actor_ref is not None
340
+ return await self._actor_ref.__xoscar_next__(self._uid)
341
+ except Exception as e:
342
+ if "StopIteration" in str(e):
343
+ raise StopAsyncIteration
344
+ else:
345
+ raise
346
+
347
+
274
348
  class AsyncActorMixin:
275
349
  @classmethod
276
350
  def default_uid(cls):
@@ -282,6 +356,10 @@ class AsyncActorMixin:
282
356
  except KeyError:
283
357
  return super().__new__(cls, *args, **kwargs)
284
358
 
359
+ def __init__(self, *args, **kwargs) -> None:
360
+ super().__init__()
361
+ self._generators: Dict[str, IteratorWrapper] = {}
362
+
285
363
  async def __post_create__(self):
286
364
  """
287
365
  Method called after actor creation
@@ -305,6 +383,93 @@ class AsyncActorMixin:
305
383
  """
306
384
  return await super().__on_receive__(message) # type: ignore
307
385
 
386
+ async def __xoscar_next__(self, generator_uid: str) -> Any:
387
+ """
388
+ Iter the next of generator.
389
+
390
+ Parameters
391
+ ----------
392
+ generator_uid: str
393
+ The uid of generator
394
+
395
+ Returns
396
+ -------
397
+ The next value of generator
398
+ """
399
+
400
+ def _wrapper(_gen):
401
+ try:
402
+ return next(_gen)
403
+ except StopIteration:
404
+ return stop
405
+
406
+ async def _async_wrapper(_gen):
407
+ try:
408
+ # anext is only available for Python >= 3.10
409
+ return await _gen.__anext__() # noqa: F821
410
+ except StopAsyncIteration:
411
+ return stop
412
+
413
+ if gen := self._generators.get(generator_uid):
414
+ stop = object()
415
+ try:
416
+ if inspect.isgenerator(gen):
417
+ r = await asyncio.to_thread(_wrapper, gen)
418
+ elif inspect.isasyncgen(gen):
419
+ r = await asyncio.create_task(_async_wrapper(gen))
420
+ else:
421
+ raise Exception(
422
+ f"The generator {generator_uid} should be a generator or an async generator, "
423
+ f"but a {type(gen)} is got."
424
+ )
425
+ except Exception as e:
426
+ logger.exception(
427
+ f"Destroy generator {generator_uid} due to an error encountered."
428
+ )
429
+ await self.__xoscar_destroy_generator__(generator_uid)
430
+ del gen # Avoid exception hold generator reference.
431
+ raise e
432
+ if r is stop:
433
+ await self.__xoscar_destroy_generator__(generator_uid)
434
+ del gen # Avoid exception hold generator reference.
435
+ raise Exception("StopIteration")
436
+ else:
437
+ return r
438
+ else:
439
+ raise RuntimeError(f"No iterator with id: {generator_uid}")
440
+
441
+ async def __xoscar_destroy_generator__(self, generator_uid: str):
442
+ """
443
+ Destroy the generator.
444
+
445
+ Parameters
446
+ ----------
447
+ generator_uid: str
448
+ The uid of generator
449
+ """
450
+ logger.debug("Destroy generator: %s", generator_uid)
451
+ self._generators.pop(generator_uid, None)
452
+
453
+
454
+ def generator(func):
455
+ need_to_thread = not asyncio.iscoroutinefunction(func)
456
+
457
+ @functools.wraps(func)
458
+ async def _wrapper(self, *args, **kwargs):
459
+ if need_to_thread:
460
+ r = await asyncio.to_thread(func, self, *args, **kwargs)
461
+ else:
462
+ r = await func(self, *args, **kwargs)
463
+ if inspect.isgenerator(r) or inspect.isasyncgen(r):
464
+ gen_uid = uuid.uuid1().hex
465
+ logger.debug("Create generator: %s", gen_uid)
466
+ self._generators[gen_uid] = r
467
+ return IteratorWrapper(gen_uid, self.address, self.uid)
468
+ else:
469
+ return r
470
+
471
+ return _wrapper
472
+
308
473
 
309
474
  class Actor(AsyncActorMixin, _Actor):
310
475
  pass
Binary file
Binary file
xoscar/core.pyx CHANGED
@@ -127,7 +127,7 @@ cdef class ActorRef:
127
127
  return create_actor_ref, (self.address, self.uid)
128
128
 
129
129
  def __getattr__(self, item):
130
- if item.startswith('_'):
130
+ if item.startswith('_') and item not in ["__xoscar_next__", "__xoscar_destroy_generator__"]:
131
131
  return object.__getattribute__(self, item)
132
132
 
133
133
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xoscar
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: Python actor framework for heterogeneous computing.
5
5
  Home-page: http://github.com/xorbitsai/xoscar
6
6
  Author: Qin Xuye
@@ -1,7 +1,7 @@
1
- xoscar-0.1.4.dist-info/RECORD,,
2
- xoscar-0.1.4.dist-info/WHEEL,sha256=DcQ_CBc5lcCpOkpgTKxtf6JlU0Ew_fM0Yq6SmO-UB_M,113
3
- xoscar-0.1.4.dist-info/top_level.txt,sha256=vYlqqY4Nys8Thm1hePIuUv8eQePdULVWMmt7lXtX_ZA,21
4
- xoscar-0.1.4.dist-info/METADATA,sha256=9VJ57HI5Evln870g8i4Ex41M4GGXVI8-n2Sj6XzSekI,9214
1
+ xoscar-0.2.1.dist-info/RECORD,,
2
+ xoscar-0.2.1.dist-info/WHEEL,sha256=DcQ_CBc5lcCpOkpgTKxtf6JlU0Ew_fM0Yq6SmO-UB_M,113
3
+ xoscar-0.2.1.dist-info/top_level.txt,sha256=vYlqqY4Nys8Thm1hePIuUv8eQePdULVWMmt7lXtX_ZA,21
4
+ xoscar-0.2.1.dist-info/METADATA,sha256=rG9DA6iIoOVLoyKK0z5tid9xhSVnWccijS9blRQyfSc,9214
5
5
  xoscar/_utils.pyx,sha256=UR1FtYXAYKIdEWR9HulEpMbSOrkQWi6xGz63d4IQmG0,7059
6
6
  xoscar/backend.py,sha256=is436OPkZfSpQXaoqTRVta5eoye_pp45RFgCstAk2hU,1850
7
7
  xoscar/core.pxd,sha256=4lBq8J0kjcXcsGuvN7Kv4xcL5liHwTTFWlqyK7XAEnw,1280
@@ -10,18 +10,18 @@ xoscar/context.pxd,sha256=qKa0OyDPZtVymftSh447m-RzFZgmz8rGqQBa7qlauvc,725
10
10
  xoscar/batch.py,sha256=DpArS0L3WYJ_HVPG-6hSYEwoAFY1mY2-mlC4Jp5M_Dw,7872
11
11
  xoscar/nvutils.py,sha256=qmW4mKLU0WB2yCs198ccQOgLL02zB7Fsa-AotO3NOmg,20412
12
12
  xoscar/constants.py,sha256=Yn59lRIOvE1VFwyuZB5G2-gxYIyhIZ1rVovbdFAR2NM,759
13
- xoscar/__init__.py,sha256=QbTOmq0iycuyylnarLBGorCd639XYQpU0MoTeBOyL-w,1706
14
- xoscar/api.py,sha256=Vu_AdyJf0GZqDaiAa1T8ZE09qo_xUKBfT4XjBs4QzR8,8324
15
- xoscar/_utils.cpython-38-darwin.so,sha256=jkCVfRqBVkTGDphcAXG1PCT3NcdzY2ZpRkh6va7KeOA,386424
13
+ xoscar/__init__.py,sha256=9BapEEmHU9OlpDOIc_4LwXNHfauP1XDW0YRnAUKZp_8,1721
14
+ xoscar/api.py,sha256=3hztPoOxg8A_mlhWyWgVP7FMXG0PATA1TP4Rbaj7A-g,13327
15
+ xoscar/_utils.cpython-38-darwin.so,sha256=yJta9Rv60X-9oVBy1bijnMpEmv0O_jpAU_IOb8lKG-I,386424
16
16
  xoscar/utils.py,sha256=TH81N2EWUDfAMdlkPYSh0juZS2EbdvvdhWx_6euQygk,14672
17
17
  xoscar/debug.py,sha256=9Z8SgE2WaKYQcyDo-5-DxEJQ533v7kWjrvCd28pSx3E,5069
18
18
  xoscar/libcpp.pxd,sha256=DJqBxLFOKL4iRr9Kale5UH3rbvPRD1x5bTSOPHFpz9I,1147
19
19
  xoscar/entrypoints.py,sha256=t-PfnqYDyjzXbV-Z-hjaQxpf_m95eSx2saAsb-V2ODY,1642
20
20
  xoscar/context.pyx,sha256=8CdgPnWcE9eOp3N600WgDQ03MCi8P73eUOGcfV7Zksg,10942
21
- xoscar/context.cpython-38-darwin.so,sha256=q3Im3Vy09aBSl03PuarZcpnq0vP1GUV4ucabpfhuSpY,480553
21
+ xoscar/context.cpython-38-darwin.so,sha256=zbXL2AFs2sQG_Ncj6e1qeQtSz-LeorNkWY77wAsylzQ,480585
22
22
  xoscar/errors.py,sha256=wBlQOKsXf0Fc4skN39tDie0YZT-VIAuLNRgoDl2pZcA,1241
23
- xoscar/core.cpython-38-darwin.so,sha256=a_Kh-HPtrfnJ_fAzc0kcOvXlEbfFFXz8XNkPbIHb3Fs,999798
24
- xoscar/core.pyx,sha256=hVnv6jM9_kqdnYnRWlsBju1Xh0_qAEEY1T2Hui05zFM,21662
23
+ xoscar/core.cpython-38-darwin.so,sha256=fSEncPwszq6Eo2JNV2SzXOqn2qcg4WkwZMfh-44Qmi4,999958
24
+ xoscar/core.pyx,sha256=Aqc2i8Fetsd5wRAPF4kL0ddnBZn3E2HRNCvup79BbQc,21730
25
25
  xoscar/driver.py,sha256=498fowtJr6b3FE8FIOA_Tc1Vwx88nfZw7p0FxrML0h4,1372
26
26
  xoscar/profiling.py,sha256=BC5OF0HzSaXv8V7w-y-B8r5gV5DgxHFoTEIF6jCMioQ,8015
27
27
  xoscar/_utils.pxd,sha256=5KYAL3jfPdejsHnrGGT2s--ZUX5SXznQWpHVSno429k,1157
@@ -47,11 +47,11 @@ xoscar/serialization/numpy.py,sha256=5Kem87CvpJmzUMp3QHk4WeHU30FoQWTJJP2SwIcaQG0
47
47
  xoscar/serialization/cuda.py,sha256=iFUEnN4SiquBIhyieyOrfw3TnKnW-tU_vYgqOxO_DrA,3758
48
48
  xoscar/serialization/scipy.py,sha256=yOEi0NB8cqQ6e2UnCZ1w006RsB7T725tIL-DM_hNcsU,2482
49
49
  xoscar/serialization/aio.py,sha256=S9e3rHMBwqqKmJtDz7KzYAqWc8w9bttA0Dj83IBfEU0,4577
50
- xoscar/serialization/core.cpython-38-darwin.so,sha256=LauwlGgUFyb1XNpy-_i4QMgx2aWhjNlsBljm5sRDrQ4,943254
50
+ xoscar/serialization/core.cpython-38-darwin.so,sha256=mYFXyJ_eCEkbRFIlMbSSvx9jDTzftwsdlFASGzsgV9g,943254
51
51
  xoscar/serialization/core.pyx,sha256=E3xIKmdI2gn99JduR3yuU_YTm-lOyG0Tkc7fZVBWCho,30131
52
52
  xoscar/backends/config.py,sha256=EG26f0GwX_f4dAhwTW77RBjiK9h8R_3JrD-rBF1bAq8,4984
53
53
  xoscar/backends/allocate_strategy.py,sha256=tC1Nbq2tJohahUwd-zoRYHEDX65wyuX8tmeY45uWj_w,4845
54
- xoscar/backends/message.cpython-38-darwin.so,sha256=gy4DoEb9HlwkherJr0LnQ-oG5j2gVDFaYrC12dmReuU,822985
54
+ xoscar/backends/message.cpython-38-darwin.so,sha256=OpmZ4lRiQvvxgGgrcU9E1F7YGs_l9mZwN7FSO8YHfi0,822985
55
55
  xoscar/backends/__init__.py,sha256=VHEBQcUWM5bj027W8EUf9PiJUAP7JoMrRw3Tsvy5ySw,643
56
56
  xoscar/backends/core.py,sha256=o6g3ZOW7PkGmiu-nNtp6I3Sd_2KkQDwOsKz-FdgRFs0,7390
57
57
  xoscar/backends/context.py,sha256=b4mDqcrA7uBsy9Rb5laxlbujCyj8GpBglpjkNcg-Mg0,15285
File without changes