xoscar 0.1.4__cp39-cp39-macosx_10_9_universal2.whl → 0.2.1__cp39-cp39-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=xX5eQQnems5GjABODHajeVXEXS9Ycsnxtza7cCoxqTA,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=xX5eQQnems5GjABODHajeVXEXS9Ycsnxtza7cCoxqTA,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,21 +10,21 @@ 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/core.cpython-39-darwin.so,sha256=VqGoTsnSNJ0397QTnDWbv7NLt7lSF_b-M6wUg8Uy1dM,999446
13
+ xoscar/__init__.py,sha256=9BapEEmHU9OlpDOIc_4LwXNHfauP1XDW0YRnAUKZp_8,1721
14
+ xoscar/api.py,sha256=3hztPoOxg8A_mlhWyWgVP7FMXG0PATA1TP4Rbaj7A-g,13327
15
+ xoscar/core.cpython-39-darwin.so,sha256=FTaVW3c2u7H_Qcde_tCAZfbV1sUlYPILS8n2kpaiBWI,999622
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
21
  xoscar/errors.py,sha256=wBlQOKsXf0Fc4skN39tDie0YZT-VIAuLNRgoDl2pZcA,1241
22
- xoscar/_utils.cpython-39-darwin.so,sha256=GOHYJQBcyFxEFu2Lx1wX98iYJLPEfs9aWmmyKRvv5O8,386168
23
- xoscar/core.pyx,sha256=hVnv6jM9_kqdnYnRWlsBju1Xh0_qAEEY1T2Hui05zFM,21662
22
+ xoscar/_utils.cpython-39-darwin.so,sha256=LK_puBgT3p_EseaAvh3cJGtpHN3Ya77JjZY0NXTbpjU,386168
23
+ xoscar/core.pyx,sha256=Aqc2i8Fetsd5wRAPF4kL0ddnBZn3E2HRNCvup79BbQc,21730
24
24
  xoscar/driver.py,sha256=498fowtJr6b3FE8FIOA_Tc1Vwx88nfZw7p0FxrML0h4,1372
25
25
  xoscar/profiling.py,sha256=BC5OF0HzSaXv8V7w-y-B8r5gV5DgxHFoTEIF6jCMioQ,8015
26
26
  xoscar/_utils.pxd,sha256=5KYAL3jfPdejsHnrGGT2s--ZUX5SXznQWpHVSno429k,1157
27
- xoscar/context.cpython-39-darwin.so,sha256=h63SiZE4XGxeXkthBGcUsndRbqC6tChm2grXlMZPT7w,463849
27
+ xoscar/context.cpython-39-darwin.so,sha256=QmdjdWZ6AA_nZ0oo15BeQO-KyYRHaZLEraL5DovcdRA,463849
28
28
  xoscar/metrics/__init__.py,sha256=9Badi7rxYikGm2dQiNCrj9GgMRBxwuR3JaEKcFZmfak,705
29
29
  xoscar/metrics/api.py,sha256=BBlMIFvVAGVfrtpeJ1YlH9Tqhy9OzGavwvGyeHcQ0Tk,8856
30
30
  xoscar/metrics/backends/__init__.py,sha256=h_JgzSqV5lP6vQ6XX_17kE4IY4BRnvKta_7VLQAL1ms,581
@@ -44,12 +44,12 @@ xoscar/serialization/pyfury.py,sha256=sifOnVMYoS82PzZEkzkfxesmMHei23k5UAUUKUyoOY
44
44
  xoscar/serialization/core.pxd,sha256=k4RoJgX5E5LGs4jdCQ7vvcn26MabXbrWoWhkO49X6YI,985
45
45
  xoscar/serialization/__init__.py,sha256=5Y_C3cYbQJIZ09LRjeCf-jrkLma7mfN8I5bznHrdsbg,846
46
46
  xoscar/serialization/numpy.py,sha256=5Kem87CvpJmzUMp3QHk4WeHU30FoQWTJJP2SwIcaQG0,2919
47
- xoscar/serialization/core.cpython-39-darwin.so,sha256=gr22byNBK6zMwfoQGjRDy69ba52jRmtWUYPo44irnsg,942806
47
+ xoscar/serialization/core.cpython-39-darwin.so,sha256=Of-4qCTnTItQ9m-a4yquX3Bg63PmCV-65JFewq8Ap_A,942838
48
48
  xoscar/serialization/cuda.py,sha256=iFUEnN4SiquBIhyieyOrfw3TnKnW-tU_vYgqOxO_DrA,3758
49
49
  xoscar/serialization/scipy.py,sha256=yOEi0NB8cqQ6e2UnCZ1w006RsB7T725tIL-DM_hNcsU,2482
50
50
  xoscar/serialization/aio.py,sha256=S9e3rHMBwqqKmJtDz7KzYAqWc8w9bttA0Dj83IBfEU0,4577
51
51
  xoscar/serialization/core.pyx,sha256=E3xIKmdI2gn99JduR3yuU_YTm-lOyG0Tkc7fZVBWCho,30131
52
- xoscar/backends/message.cpython-39-darwin.so,sha256=e_Xo8h5ZnNNGWD2Ze42G5Lsl27skMlevWxTpqd0kcBc,822825
52
+ xoscar/backends/message.cpython-39-darwin.so,sha256=sfCAbAeQIcm6bY5C1BtV9Gciz19pfZp6awkpaWkliZc,822825
53
53
  xoscar/backends/config.py,sha256=EG26f0GwX_f4dAhwTW77RBjiK9h8R_3JrD-rBF1bAq8,4984
54
54
  xoscar/backends/allocate_strategy.py,sha256=tC1Nbq2tJohahUwd-zoRYHEDX65wyuX8tmeY45uWj_w,4845
55
55
  xoscar/backends/__init__.py,sha256=VHEBQcUWM5bj027W8EUf9PiJUAP7JoMrRw3Tsvy5ySw,643
File without changes