diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2014-11-21 01:37:36 +0100 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2014-11-21 01:37:36 +0100 |
commit | 77ca2876b20591dc450e5a3137804182d9fb0fd8 (patch) | |
tree | e29f2ae0405473d22be21f11703398e40ba6737e | |
parent | 97a2f28ba38ec6231c21bb4f92758c27c39d1ee4 (diff) | |
download | aioeventlet-77ca2876b20591dc450e5a3137804182d9fb0fd8.tar.gz |
In debug mode, detect calls to call_soon() from greenthreads which are not
threadsafe (would not wake up the event loop).
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | aiogreen.py | 8 | ||||
-rw-r--r-- | tests/test_eventlet.py | 26 |
3 files changed, 51 insertions, 1 deletions
@@ -4,6 +4,22 @@ asyncio event loop scheduling callbacks in eventlet. * aiogreen at PyPI: https://pypi.python.org/pypi/aiogreen +Usage +===== + +aiogreen implements the asyncio API, see asyncio documentation: +https://docs.python.org/dev/library/asyncio.html + +To support Python 2, you can use Trollius which uses ``yield`` instead +of ``yield from`` for coroutines: +http://trollius.readthedocs.org/ + +Using the event loop from greenthreads is not safe: calls to the event loop +must be passed to ``call_soon_threadsafe()``. Example to stop the event loop: + + eventlet.spawn(loop.call_soon_threadsafe, loop.stop) + + Installation ============ @@ -87,6 +103,8 @@ Changes: in eventlet. * add_reader() and add_writer() now cancels the previous handle and sets a new handle +* In debug mode, detect calls to call_soon() from greenthreads which are not + threadsafe (would not wake up the event loop). 2014-11-19: version 0.1 ----------------------- diff --git a/aiogreen.py b/aiogreen.py index a57a47a..3a46956 100644 --- a/aiogreen.py +++ b/aiogreen.py @@ -199,6 +199,14 @@ class EventLoop(asyncio.SelectorEventLoop): def time(self): return self._hub.clock() + def _assert_is_current_event_loop(self): + super(EventLoop, self)._assert_is_current_event_loop() + if self._selector._event: + # call_soon() must not be called while selector.select() is + # running, it does not wake up the event loop + raise RuntimeError( + "Non-thread-safe operation invoked from a greenthread") + class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): _loop_factory = EventLoop diff --git a/tests/test_eventlet.py b/tests/test_eventlet.py index d50c8ee..9e6b699 100644 --- a/tests/test_eventlet.py +++ b/tests/test_eventlet.py @@ -2,6 +2,30 @@ import eventlet import tests class EventletTests(tests.TestCase): + def test_stop(self): + def func(): + eventlet.spawn(self.loop.call_soon_threadsafe, self.loop.stop) + + def schedule_greenthread(): + eventlet.spawn(func) + + self.loop.call_soon(schedule_greenthread) + self.loop.run_forever() + + def test_soon(self): + result = [] + + def func(): + result.append("spawn") + self.loop.call_soon_threadsafe(self.loop.stop) + + def schedule_greenthread(): + eventlet.spawn(func) + + self.loop.call_soon(schedule_greenthread) + self.loop.run_forever() + self.assertEqual(result, ["spawn"]) + def test_soon_spawn(self): result = [] @@ -14,7 +38,7 @@ class EventletTests(tests.TestCase): def schedule_greenthread(): eventlet.spawn(func1) - eventlet.spawn_after(0.001, func2) + eventlet.spawn_after(0.010, func2) self.loop.call_soon(schedule_greenthread) self.loop.run_forever() |