Skip to content

Document that "multiprocessing.get_context()" is also setting the context globally #109070

Open
@Delgan

Description

@Delgan

Documentation

Hi.

It's not clear from the documentation that calling multiprocessing.get_context() (with method=None) has the side effect of also setting the default context globally, preventing future usage of multiprocessing.set_start_method().

import multiprocessing

default_context = multiprocessing.get_context()  # "Fork" on Linux.
multiprocessing.set_start_method("spawn")  # Error.

Which causes:

Traceback (most recent call last):
  File "/home/delgan/test.py", line 5, in <module>
    multiprocessing.set_start_method("spawn")  # Error raised.
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/multiprocessing/context.py", line 247, in set_start_method
    raise RuntimeError('context has already been set')
RuntimeError: context has already been set

This is a surprising behavior because calling multiprocessing.get_context("fork") then multiprocessing.set_start_method("spawn") works perfectly fine. I assumed calling get_context(method=None) would just create a context using the default method ("fork" on Linux, "spawn" otherwise) but there is visibly more to it than that.


I have a library allowing user to specify the multiprocessing.Context of their choice:

def function(context=None):
    if context is None:
        context = multiprocessing.get_context()
    pipe = context.Pipe()
    ...

This recipe looks correct, but it is not. It will cause a RuntimeError if the user or another third-party library tries to call multiprocesing.set_start_method() after using my function.

I'll probably need to refactor it to something like that:

def function(context=None):
    if context is None:
        start_method = multiprocessing.get_start_method(allow_none=True)
        if start_method is not None:
            context = multiprocessing.get_context(start_method)
        elif os.name == "posix":
            context = multiprocessing.get_context("fork")
        else:
            context = multiprocessing.get_context("spawn")
    pipe = context.Pipe()
    ...

I wonder if there shouldn't be a method to retrieve the current context without setting one if there is none?
I would like to be able to use a Context just like if I was using multiprocessing directly.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions