From 8e409cebad42032bb7d0f2cadd8b1e36081d98af Mon Sep 17 00:00:00 2001 From: Eric W Date: Fri, 30 Oct 2020 05:56:28 +0100 Subject: [PATCH] bpo-42160: tempfile: Reduce overhead of pid check. (GH-22997) The _RandomSequence class in tempfile used to check the current pid every time its rng property was used. This commit replaces this code with `os.register_at_fork` to reduce the overhead. --- Lib/tempfile.py | 22 +++++++++---------- Lib/test/test_tempfile.py | 4 ++-- .../2020-10-27-00-42-09.bpo-42160.eiLOCi.rst | 1 + 3 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-27-00-42-09.bpo-42160.eiLOCi.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 770f72c2529..1bc5c71fd03 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -129,24 +129,22 @@ class _RandomNameSequence: _RandomNameSequence is an iterator.""" - characters = "abcdefghijklmnopqrstuvwxyz0123456789_" - - @property - def rng(self): - cur_pid = _os.getpid() - if cur_pid != getattr(self, '_rng_pid', None): - self._rng = _Random() - self._rng_pid = cur_pid - return self._rng + def __init__(self, characters="abcdefghijklmnopqrstuvwxyz0123456789_", length=8, rng=None): + if rng is None: + rng = _Random() + if hasattr(_os, "fork"): + # prevent same state after fork + _os.register_at_fork(after_in_child=rng.seed) + self.rng = rng + self.characters = characters + self.length = length def __iter__(self): return self def __next__(self): c = self.characters - choose = self.rng.choice - letters = [choose(c) for dummy in range(8)] - return ''.join(letters) + return ''.join(self.rng.choices(c, k=self.length)) def _candidate_tempdir_list(): """Generate a list of candidate temporary directories which diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 8ace883d74b..77d710efaf1 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -153,8 +153,8 @@ class TestRandomNameSequence(BaseTestCase): self.r = tempfile._RandomNameSequence() super().setUp() - def test_get_six_char_str(self): - # _RandomNameSequence returns a six-character string + def test_get_eight_char_str(self): + # _RandomNameSequence returns a eight-character string s = next(self.r) self.nameCheck(s, '', '', '') diff --git a/Misc/NEWS.d/next/Library/2020-10-27-00-42-09.bpo-42160.eiLOCi.rst b/Misc/NEWS.d/next/Library/2020-10-27-00-42-09.bpo-42160.eiLOCi.rst new file mode 100644 index 00000000000..c5f3091283a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-27-00-42-09.bpo-42160.eiLOCi.rst @@ -0,0 +1 @@ +Replaced pid check in ``tempfile._RandomNameSequence`` with ``os.register_at_fork`` to reduce overhead.