I am learning the Trio API and ran into some surprising behavior (at least to me). It isn’t clearly stated in the Trio documentation, but is it true that a trio.Event() can only be created from within an event loop? The reason why this is significant is that Event objects are often created within __init__
such as:
class C:
def __init__( self ):
self.flag = trio.Event()
Sometimes, when I run the code, a later call to self.flag.set()
does not unblock tasks waiting for the flag to be set. After much hair pulling, I think the difference ended up being when I create an instance of C
. If I create it within a task, then the event seems to work. If I create the instance before the loop runs and pass the instance into the loop, then the event fails.
If this is a true restriction then the documentation really needs to be updated to warn users to create their objects only within a running task. The fact that __init__
cannot be asynchronous seems to encourage object creation via async def factory_method
instead of __init__
but in this case, not knowing the restriction makes it really easy to do the wrong thing—and fixing the bug isn’t obvious (because it may involve refactoring initialization code that looks right, but the objects are created at the wrong time.)
The same could be said for the other synchronization primitives: if their implementation requires an event loop at the time of creation (and not just at the time of calling set()
or wait()
) then it would be helpful to document this.