Author martius
Recipients christian.heimes, gvanrossum, martius, neologix, vstinner, yselivanov
Date 2015-05-26.18:23:46
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <CAOEXP8gRX4Pf-UtBin-TwoRMzbXYzLcZ-oNNXh_iMbfH+qBnUg@mail.gmail.com>
In-reply-to <1432657212.39.0.74192376237.issue21998@psf.upfronthosting.co.za>
Content
Hi,

My patch was a variation of haypo's patch. The goal was to duplicate the
loop and its internal objects (loop and self pipes) without changing much
to its state from the outside (keeping callbacks and active tasks). I
wanted to be conservative with this patch, but it is not the option I
prefer.

I think that raising a RuntimeError in the child is fine, but may not be
enough:

Imho, saying "the loop can't be used anymore in the child" is fine, but "a
process in which lives an asyncio loop must not be forked" is too
restrictive (I'm not thinking of the fork+exec case, which is probably fine
anyway) because a library may rely on child processes, for instance.

Hence, we should allow a program to fork and eventually dispose the
resources of the loop by calling loop.close() - or any other mechanism that
you see fit (clearing all references to the loop is tedious because of the
global default event loop and the cycles between futures/tasks and the
loop).

However, the normal loop.close() sequence will unregister all the fds
registered to the selector, which will impact the parent. Under Linux with
epoll, it's fine if we only close the selector.

I would therefore, in the child after a fork, close the loop without
breaking the selector state (closing without unregister()'ing fds), unset
the default loop so get_event_loop() would create a new loop, then raise
RuntimeError.

I can elaborate on the use case I care about, but in a nutshell, doing so
would allow to spawn worker processes able to create their own loop without
requiring an idle "blank" child process that would be used as a base for
the workers. It adds the benefit, for instance, of allowing to share data
between the parent and the child leveraging OS copy-on-write.

2015-05-26 18:20 GMT+02:00 Yury Selivanov <report@bugs.python.org>:

>
> Yury Selivanov added the comment:
>
> > How do other event loops handle fork? Twisted, Tornado, libuv, libev,
> libevent, etc.
>
> It looks like using fork() while an event loop is running isn't
> recommended in any of the above.  If I understand the code correctly, libev
> & gevent reinitialize loops in the forked process (essentially, you have a
> new loop).
>
> I think we have the following options:
>
> 1. Document that using fork() is not recommended.
>
> 2. Detect fork() and re-initialize event loop in the child process
> (cleaning-up callback queues, re-initializing selectors, creating new
> self-pipe).
>
> 3. Detect fork() and raise a RuntimeError.  Document that asyncio event
> loop does not support forking at all.
>
> 4. The most recent patch by Martin detects the fork() and reinitializes
> self-pipe and selector (although all FDs are kept in the new selector).
> I'm not sure I understand this option.
>
> I'm torn between 2 & 3.  Guido, Victor, Martin, what do you think?
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue21998>
> _______________________________________
>
History
Date User Action Args
2015-05-26 18:23:46martiussetrecipients: + martius, gvanrossum, vstinner, christian.heimes, neologix, yselivanov
2015-05-26 18:23:46martiuslinkissue21998 messages
2015-05-26 18:23:46martiuscreate