This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: asyncio: Add context manager to BaseEventLoop?
Type: behavior Stage: resolved
Components: Versions: Python 3.4
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: gvanrossum, larry, pitrou, vstinner
Priority: normal Keywords: patch

Created on 2013-12-02 11:45 by vstinner, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
eventloop_context_manager.patch vstinner, 2013-12-02 11:45 review
Messages (9)
msg205004 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-02 11:45
The BaseSelectorEventLoop class (inherited by UnixSelectorEventLoop) creates a socketpair in its constructor. So if you don't call close(), the socketpair may stay alive.

It would be convinient to support the context manager to be able to write:

with asyncio.get_event_loop() as loop
   # ... prepare loop ...
   loop.run_forever()
# KeyboardInterrupt or SystemExit: loop.close() is called

Hello World examples don't call close(), so the sockets are not closed when the example is stopped using CTRL+c.

Attached patch adds __enter__/__exit__ methods to BaseEventLoop and use it in the two Hello World examples.
msg205020 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-02 15:53
Isn't this mostly political correctness? The hello world programs really don't need to worry about closing the socket pair. Most real-world programs don't either -- the recommended pattern is just to loop until the end of the world, and then exit the program.

I'd like to counter with some political correctness of my own -- this smells like a new feature and therefore shouldn't be added to 3.4.  (Adding Larry -- if Larry is fine with making small additions to asyncio during the beta, I am also okay with adding this.)
msg205022 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-12-02 15:59
There's another problem: get_event_loop() returns a persistent object, not a new instance every time. So you can't write:

  with get_event_loop() as loop:
      # ...

twice in a row if the loop is closed at the end of the "with" block.
msg205025 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-02 16:22
"There's another problem: get_event_loop() returns a persistent object, not a new instance every time."

Oh, I didn't know that, but it makes sense. It should be documented.

It is possible to create a second event loop, only used to execute a short one-shot task? I don't see how to instanciate a second event loop.
msg205027 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-02 16:47
To create a new event loop, use set_event_loop(new_event_loop()).  You have to do that if you want an event loop in a thread; it's also handy in unit tests.  (However asyncio's own unit tests only call new_event_loop() and pass it around explicitly with loop=...; they set the default event loop to None with set_event_loop(None).)

Creating a second event loop (in the same thread) while you already have an event loop is fraught with problems -- while the second one is running any events associated with the first one won't fire.

(This API is not random -- it is intentionally restricted to allow certain platform event loops to be adapted.)
msg205048 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2013-12-02 20:07
Since this is a new library in 3.4, I can be more flexible.  And since you're talking about adding a new feature (rather than changing or removing an existing feature), this has a vanishingly small chance of screwing anything up.  Therefore I'm okay with adding this feature.

I suppose Python 3.4 only supports platforms that auto-close sockets at the end of a process, but I dimly recall Windows 95/98/ME didn't do that.  And there are crazy people porting to platforms like Amiga.  And I can hardly disapprove of something as wholesome as making sure people call .close().  So if Guido says okay, go ahead and check it in.
msg205050 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-02 20:18
But there is Antoine's point.  This makes

  with get_event_loop() as loop:
      <do stuff with loop>

an attractive nuisance if it's used in the wrong place.
msg205056 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2013-12-02 20:50
Okay, yeah.  I assumed calling .close() was best practice.  If it's not, then...

Guido, since this is your library, I delegate the decision to you.  You guys can add this any time before I tag beta 2 if Guido's on board.
msg205062 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-02 22:49
Well, calling close() is best practice *if you own the loop*.  But the thing is that you may not own what get_event_loop() returns, and in fact in most cases where it is called you don't own it.  This is very different from files:

  with open(...) as f:
      ...

In that idiom you clearly own f.  Both of these are also very different from locks and the like, because you can repeatedly acquire and release a lock (but you can only close a file or event loop once).

I tried to come up with a design for a helper that in __enter__() creates a new event loop and makes it the current event loop, then in __exit__() closes it and sets the current event loop to None.  But this doesn't work well with the way get_event_loop() can sometimes auto-creates the loop.

Therefore I am closing this as "rejected".
History
Date User Action Args
2022-04-11 14:57:54adminsetgithub: 64059
2013-12-02 22:49:56gvanrossumsetstatus: open -> closed
type: behavior
messages: + msg205062

resolution: rejected
stage: resolved
2013-12-02 20:50:20larrysetmessages: + msg205056
2013-12-02 20:18:56gvanrossumsetmessages: + msg205050
2013-12-02 20:07:07larrysetmessages: + msg205048
2013-12-02 16:47:41gvanrossumsetmessages: + msg205027
2013-12-02 16:22:08vstinnersetmessages: + msg205025
2013-12-02 15:59:47pitrousetmessages: + msg205022
2013-12-02 15:53:11gvanrossumsetnosy: + larry
messages: + msg205020
2013-12-02 11:45:59vstinnercreate