-
Couldn't load subscription status.
- Fork 2
Open
Description
Out of curiosity, I tried incorporating coroutine handling into Runtime so that async code could be run, basically implementing an Async ability. This is a very partial POC.
patch for runtime.py:
2c2,4
<
---
> import types
> import asyncio
> import threading
35c37,39
<
---
> object.__setattr__(self, "loop", asyncio.new_event_loop())
> self.loop._thread_id = threading.get_ident()
> asyncio.events._set_running_loop(self.loop)
134a135
> from inspect import isawaitable
139a141,148
> case co if isawaitable(co):
> if isinstance(co, types.CoroutineType):
> task = self.loop.create_task(co)
> else:
> task = co
> while not task.done():
> self.loop._run_once()
> effect.send(task.result())Makes this work:
import asyncio
from dataclasses import dataclass
from typing import Never, Awaitable, Iterable
import httpx
from stateless import Effect, Runtime, Depend, depend, catch, throws
SYNC = False
async def gather[R](cos: Iterable[Awaitable[R]]) -> list[R]:
if SYNC:
return [await c for c in cos]
return await asyncio.gather(*cos)
@dataclass(frozen=True)
class HTTP:
client: httpx.AsyncClient
def get(self, url, *args, **kwargs) -> Awaitable[httpx.Response]:
return self.client.get(url, *args, **kwargs)
def http_client() -> Depend[Never, HTTP]:
client = yield httpx.AsyncClient().__aenter__()
return HTTP(client)
def get_concurrently():
http = yield from depend(HTTP)
result = yield gather(http.get(f"https://{x}.com") for x in ['google', 'reddit', 'xkcd'])
return result
runtime = Runtime().use_effect(http_client())
e = get_concurrently()
runtime.run(e)Changing SYNC to True doubles the runtime, which verifies that the coroutines originally run concurrently.
Problems:
- doesn't propagate errors from
HTTP.get()to the caller - yielding coroutines, which are not abilities, mess with static typing
HTTP.get()invocations can't be encapsulated in effects (functions) becausegather()can't deal with plain generators. Solving this probably requires implementing a special flavor ofgather()that drives each generator until it yields a coroutine, collects them, and callsgather(), repeating until all generators are exhausted
Metadata
Metadata
Assignees
Labels
No labels