Use multiprocessing start_method "forkserver" (#4306)

* Use `multiprocessing` `start_method` `"forkserver"`

Alternative to PR #4305

* Add link to comment under PR #4105

* Unconditionally `pytest.skip("DEADLOCK")` for PyPy Windows

* Remove `SKIP_IF_DEADLOCK` entirely, for simplicity. Hopefully this PR will resolve the deadlocks for good.

* Add "In a nutshell" comment, in response to request by @EricCousineau-TRI
This commit is contained in:
Ralf W. Grosse-Kunstleve 2022-11-22 17:17:02 -08:00 committed by GitHub
parent 48949222c6
commit 9c18a74e37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 14 additions and 2 deletions

View File

@ -7,6 +7,8 @@ Adds docstring and exceptions message sanitizers.
import contextlib import contextlib
import difflib import difflib
import gc import gc
import multiprocessing
import os
import re import re
import textwrap import textwrap
@ -15,6 +17,16 @@ import pytest
# Early diagnostic for failed imports # Early diagnostic for failed imports
import pybind11_tests import pybind11_tests
if os.name != "nt":
# Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592
# In a nutshell: fork() after starting threads == flakiness in the form of deadlocks.
# It is actually a well-known pitfall, unfortunately without guard rails.
# "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py,
# visit the issuecomment link above for details).
# Windows does not have fork() and the associated pitfall, therefore it is best left
# running with defaults.
multiprocessing.set_start_method("forkserver")
_long_marker = re.compile(r"([0-9])L") _long_marker = re.compile(r"([0-9])L")
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+") _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")

View File

@ -5,6 +5,7 @@ import time
import pytest import pytest
import env
from pybind11_tests import gil_scoped as m from pybind11_tests import gil_scoped as m
@ -144,7 +145,6 @@ def _intentional_deadlock():
ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK = ALL_BASIC_TESTS + (_intentional_deadlock,) ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK = ALL_BASIC_TESTS + (_intentional_deadlock,)
SKIP_IF_DEADLOCK = True # See PR #4216
def _run_in_process(target, *args, **kwargs): def _run_in_process(target, *args, **kwargs):
@ -181,7 +181,7 @@ def _run_in_process(target, *args, **kwargs):
elif process.exitcode is None: elif process.exitcode is None:
assert t_delta > 0.9 * timeout assert t_delta > 0.9 * timeout
msg = "DEADLOCK, most likely, exactly what this test is meant to detect." msg = "DEADLOCK, most likely, exactly what this test is meant to detect."
if SKIP_IF_DEADLOCK: if env.PYPY and env.WIN:
pytest.skip(msg) pytest.skip(msg)
raise RuntimeError(msg) raise RuntimeError(msg)
return process.exitcode return process.exitcode