Skip to content

Instantly share code, notes, and snippets.

@gsakkis
Last active January 7, 2024 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gsakkis/18bc444607a590fe3f084a77aa54b4c2 to your computer and use it in GitHub Desktop.
Save gsakkis/18bc444607a590fe3f084a77aa54b4c2 to your computer and use it in GitHub Desktop.
Awaiting async code from sync
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