pythongeventpython-trio

Call trio from inside a greenlet


I've tried this:

import trio
from gevent import monkey, spawn

monkey.patch_all()

async def async_double(x):
    return 2 * x

def run():
    return trio.run(async_double, 3)

g = spawn(run)
g.join()

But I get an error:

Traceback (most recent call last):
  File "src/gevent/greenlet.py", line 908, in gevent._gevent_cgreenlet.Greenlet.run
  File "/Users/xxx/t.py", line 10, in run
    return trio.run(async_double, 3)
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/_core/_run.py", line 1990, in run
    runner = setup_runner(
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/_core/_run.py", line 1885, in setup_runner
    io_manager = TheIOManager()
  File "<attrs generated init trio._core._io_kqueue.KqueueIOManager>", line 15, in __init__
    self.__attrs_post_init__()
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/_core/_io_kqueue.py", line 33, in __attrs_post_init__
    force_wakeup_event = select.kevent(
AttributeError: module 'select' has no attribute 'kevent'
2023-07-28T21:06:31Z <Greenlet at 0x105d22370: run> failed with AttributeError

I've also tried importing and patching gevent first, but that fails even before running:

from gevent import monkey, spawn
monkey.patch_all()
import trio

Traceback:

  File "/Users/xxx/t.py", line 3, in <module>
    import trio
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/__init__.py", line 18, in <module>
    from ._core import (
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/_core/__init__.py", line 27, in <module>
    from ._run import (
  File "/Users/xxx/Library/Python/3.9/lib/python/site-packages/trio/_core/_run.py", line 2458, in <module>
    raise NotImplementedError("unsupported platform")
NotImplementedError: unsupported platform

I think I managed to get the first approach (importing trio first) working at times (but that code was a little different and a lot more complex), but I want to know if that was just lucky and would have issues later on.

This is on MacOS, but it needs to be cross platform.

Edit: Note that "This is impossible, dont even try" is a completely acceptable answer, as long as it is properly motivated :)

Edit: My end goal is to allow users of Locust (a load test framework which uses gevent for concurrency) to also run things that depend on trio (like for example Playwright)


Solution

  • I managed to get the first approach (importing trio first) working at times ..., but I want to know if that was just lucky and would have issues later on.

    Yes, it would have issues on macOS (fine for win32 and linux) if actually using trio.

    On macOS, trio _run.py enters kqueue block with import KqueueIOManager as TheIOManager.
    KqueueIOManager calls select.kevent, which is removed with kqueue in the select patch.
    Removal of kqueue if patch before trio causes _run.py to enter else block with that raise.

    You can skip it and let trio continue to use the blocking kqueue by not doing aggressive patch:

    from gevent import monkey, spawn
    # monkey.patch_all()                # Change this to
    monkey.patch_all(aggressive=False)  # either this
    # monkey.patch_all(select=False)    # or not patch select at all
    import trio