Last active
June 23, 2024 17:26
-
-
Save gsakkis/18bc444607a590fe3f084a77aa54b4c2 to your computer and use it in GitHub Desktop.
Awaiting async code from sync
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import threading | |
from typing import Any, Awaitable, Iterable, Optional, TypeVar | |
T = TypeVar("T") | |
class sync_await: | |
def __enter__(self) -> "sync_await": | |
self._loop = asyncio.new_event_loop() | |
self._looper = threading.Thread(target=self._loop.run_forever, daemon=True) | |
self._looper.start() | |
return self | |
def __call__(self, coro: Awaitable[T], timeout: Optional[float] = None) -> T: | |
return asyncio.run_coroutine_threadsafe(coro, self._loop).result(timeout) | |
def __exit__(self, *exc_info: Any) -> None: | |
self._loop.call_soon_threadsafe(self._loop.stop) | |
self._looper.join() | |
self._loop.close() | |
async def asquare(n: int) -> int: | |
print(f"started asquare({n}) [{threading.current_thread().name}]") | |
await asyncio.sleep(0.1) | |
print(f"finished asquare({n}) [{threading.current_thread().name}]") | |
return n * n | |
def first_even(numbers: Iterable[int]) -> int: | |
return next(n for n in numbers if n % 2 == 0) | |
def main(numbers: Iterable[int]) -> tuple[int, int]: | |
coros = map(asquare, numbers) | |
with sync_await() as await_: | |
x = await_(next(coros)) | |
y = first_even(map(await_, coros)) | |
return x, y | |
async def amain(numbers: Iterable[int]) -> tuple[int, int]: | |
coros = map(asquare, numbers) | |
with sync_await() as await_: | |
x = await next(coros) | |
# TypeError: 'async_generator' object is not iterable | |
# y = first_even(await c for c in coros) | |
y = first_even(map(await_, coros)) | |
return x, y | |
if __name__ == "__main__": | |
nums = [8, 3, 5, 10, 11, 12, 13] | |
print("* main(nums)") | |
print(main(nums)) | |
print() | |
print("* asyncio.run(amain(nums))") | |
print(asyncio.run(amain(nums))) | |
# ============= Output ======================== | |
# | |
# * main(nums) | |
# started asquare(8) [Thread-1 (run_forever)] | |
# finished asquare(8) [Thread-1 (run_forever)] | |
# started asquare(3) [Thread-1 (run_forever)] | |
# finished asquare(3) [Thread-1 (run_forever)] | |
# started asquare(5) [Thread-1 (run_forever)] | |
# finished asquare(5) [Thread-1 (run_forever)] | |
# started asquare(10) [Thread-1 (run_forever)] | |
# finished asquare(10) [Thread-1 (run_forever)] | |
# (64, 100) | |
# | |
# * asyncio.run(amain(nums)) | |
# started asquare(8) [MainThread] | |
# finished asquare(8) [MainThread] | |
# started asquare(3) [Thread-2 (run_forever)] | |
# finished asquare(3) [Thread-2 (run_forever)] | |
# started asquare(5) [Thread-2 (run_forever)] | |
# finished asquare(5) [Thread-2 (run_forever)] | |
# started asquare(10) [Thread-2 (run_forever)] | |
# finished asquare(10) [Thread-2 (run_forever)] | |
# (64, 100) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment