New submission from Nathaniel Smith <n...@pobox.com>:
Asyncio needs a way to schedule work from other threads; and it also needs a way to scheduler work from code that can run at arbitrary times in the same thread, such as signal handlers or object finalizers ("reentrant contexts"). Currently loop.call_soon_threadsafe is documented to be the way to schedule work from other threads, but there is no documented way to schedule work from reentrant contexts. These are not quite the same thing, because reentrant contexts block the main thread while they're running. Generally, making code safe to call from __del__ or signal handlers is strictly harder than making it safe to call from other threads. (See bpo-14976 for an example of stdlib code being thread-safe but not reentrant-safe.) Technically speaking, this means that right now, if you need to call an asyncio API from a __del__ method, then the only officially supported way to do that is to write something like: def __del__(self): def actual_cleanup_code(): ... def thread_dispatcher(): loop.call_soon_threadsafe(actual_cleanup_code) thread = threading.Thread(target=thread_dispatcher) thread.start() But this is kind of silly. There should be some equivalent of loop.call_soon that *is* safe to call from reentrant contexts, so we could just write: def __del__(self): def actual_cleanup_code(): ... loop.call_soon_reentrant_safe(actual_cleanup_code) But... it doesn't really make sense to add a new method for this, since the desired semantics are strictly more powerful than the current loop.call_soon_threadsafe. Instead, we should tighten the guarantees on call_soon_threadsafe, by documenting that it's safe to use from reentrant contexts. Also, AFAICT the stdlib's implementation of call_soon_threadsafe is already reentrant-safe, so this wouldn't require any changes to stdlib code, only to the docs. But it would provide an additional formal guarantee that user-level code could take advantage of, and impose an additional constraint on developers of third-party loops. (I don't think the constraint is *too* onerous, fortunately. It's quite tricky to implement a version of call_soon that's thread-safe, reentrant-safe, *and* guarantees that the callback will eventually be invoked, even if call_soon races with loop shutdown. But in asyncio, all variants of call_soon are allowed to silently drop callbacks at loop shutdown, which makes this much easier.) ---------- components: asyncio messages: 327618 nosy: asvetlov, njs, yselivanov priority: normal severity: normal status: open title: loop.call_soon_threadsafe should be documented to be re-entrant-safe too versions: Python 3.8 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue34968> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com