| 4 | # - python python/ccxt/pro/test/base/test_close.py |
| 5 | # - python python/ccxt/pro/test/base/test_future.py |
| 6 | class Future(asyncio.Future): |
| 7 | |
| 8 | def resolve(self, result=None): |
| 9 | if not self.done(): |
| 10 | self.set_result(result) |
| 11 | |
| 12 | def reject(self, error=None): |
| 13 | if not self.done(): |
| 14 | self.set_exception(error) |
| 15 | |
| 16 | @classmethod |
| 17 | def race(cls, futures): |
| 18 | """ |
| 19 | Return a Future that resolves/rejects with the first completed input future. |
| 20 | |
| 21 | IMPORTANT: |
| 22 | - No asyncio.create_task(asyncio.wait(...)) => avoids massive Task churn. |
| 23 | - We attach done callbacks and detach them immediately once a winner is chosen. |
| 24 | """ |
| 25 | |
| 26 | out = cls() |
| 27 | |
| 28 | if not futures: |
| 29 | out.set_exception(Exception("Future.race() called with empty futures")) |
| 30 | return out |
| 31 | |
| 32 | callbacks = {} # future -> callback |
| 33 | |
| 34 | def detach_all(): |
| 35 | for f, cb in list(callbacks.items()): |
| 36 | try: |
| 37 | f.remove_done_callback(cb) |
| 38 | except Exception: |
| 39 | pass |
| 40 | callbacks.clear() |
| 41 | |
| 42 | def settle_from(f): |
| 43 | if out.done(): |
| 44 | detach_all() |
| 45 | return |
| 46 | try: |
| 47 | if f.cancelled(): |
| 48 | out.cancel() |
| 49 | return |
| 50 | err = f.exception() |
| 51 | if err is not None: |
| 52 | out.set_exception(err) |
| 53 | else: |
| 54 | out.set_result(f.result()) |
| 55 | finally: |
| 56 | detach_all() |
| 57 | |
| 58 | # Fast path: if any future is already done, settle immediately. |
| 59 | for f in futures: |
| 60 | if f.done(): |
| 61 | settle_from(f) |
| 62 | return out |
| 63 |
no outgoing calls
searching dependent graphs…