Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a46e960

Browse files
authored
gh-109649: Use os.process_cpu_count() (#110165)
Replace os.cpu_count() with os.process_cpu_count() in modules: * compileall * concurrent.futures * multiprocessing Replace os.cpu_count() with os.process_cpu_count() in programs: * _decimal deccheck.py test * freeze.py * multissltests.py * python -m test (regrtest) * wasm_build.py Other changes: * test.pythoninfo logs os.process_cpu_count(). * regrtest gets os.process_cpu_count() / os.cpu_count() in headers.
1 parent 53eb9a6 commit a46e960

File tree

16 files changed

+50
-16
lines changed

16 files changed

+50
-16
lines changed

Doc/library/compileall.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ compile Python sources.
9090
.. cmdoption:: -j N
9191

9292
Use *N* workers to compile the files within the given directory.
93-
If ``0`` is used, then the result of :func:`os.cpu_count()`
93+
If ``0`` is used, then the result of :func:`os.process_cpu_count()`
9494
will be used.
9595

9696
.. cmdoption:: --invalidation-mode [timestamp|checked-hash|unchecked-hash]

Doc/library/concurrent.futures.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ And::
188188
ThreadPoolExecutor now reuses idle worker threads before starting
189189
*max_workers* worker threads too.
190190

191+
.. versionchanged:: 3.13
192+
Default value of *max_workers* is changed to
193+
``min(32, (os.process_cpu_count() or 1) + 4)``.
194+
191195

192196
.. _threadpoolexecutor-example:
193197

@@ -243,7 +247,7 @@ to a :class:`ProcessPoolExecutor` will result in deadlock.
243247

244248
An :class:`Executor` subclass that executes calls asynchronously using a pool
245249
of at most *max_workers* processes. If *max_workers* is ``None`` or not
246-
given, it will default to the number of processors on the machine.
250+
given, it will default to :func:`os.process_cpu_count`.
247251
If *max_workers* is less than or equal to ``0``, then a :exc:`ValueError`
248252
will be raised.
249253
On Windows, *max_workers* must be less than or equal to ``61``. If it is not
@@ -301,6 +305,10 @@ to a :class:`ProcessPoolExecutor` will result in deadlock.
301305
different start method. See the :func:`os.fork` documentation for
302306
further explanation.
303307

308+
.. versionchanged:: 3.13
309+
*max_workers* uses :func:`os.process_cpu_count` by default, instead of
310+
:func:`os.cpu_count`.
311+
304312
.. _processpoolexecutor-example:
305313

306314
ProcessPoolExecutor Example

Doc/library/multiprocessing.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -996,13 +996,13 @@ Miscellaneous
996996

997997
This number is not equivalent to the number of CPUs the current process can
998998
use. The number of usable CPUs can be obtained with
999-
``len(os.sched_getaffinity(0))``
999+
:func:`os.process_cpu_count`.
10001000

10011001
When the number of CPUs cannot be determined a :exc:`NotImplementedError`
10021002
is raised.
10031003

10041004
.. seealso::
1005-
:func:`os.cpu_count`
1005+
:func:`os.cpu_count` and :func:`os.process_cpu_count`
10061006

10071007
.. function:: current_process()
10081008

@@ -2214,7 +2214,7 @@ with the :class:`Pool` class.
22142214
callbacks and has a parallel map implementation.
22152215

22162216
*processes* is the number of worker processes to use. If *processes* is
2217-
``None`` then the number returned by :func:`os.cpu_count` is used.
2217+
``None`` then the number returned by :func:`os.process_cpu_count` is used.
22182218

22192219
If *initializer* is not ``None`` then each worker process will call
22202220
``initializer(*initargs)`` when it starts.
@@ -2249,6 +2249,10 @@ with the :class:`Pool` class.
22492249
.. versionadded:: 3.4
22502250
*context*
22512251

2252+
.. versionchanged:: 3.13
2253+
*processes* uses :func:`os.process_cpu_count` by default, instead of
2254+
:func:`os.cpu_count`.
2255+
22522256
.. note::
22532257

22542258
Worker processes within a :class:`Pool` typically live for the complete
@@ -2775,7 +2779,7 @@ worker threads rather than worker processes.
27752779
:meth:`~multiprocessing.pool.Pool.terminate` manually.
27762780

27772781
*processes* is the number of worker threads to use. If *processes* is
2778-
``None`` then the number returned by :func:`os.cpu_count` is used.
2782+
``None`` then the number returned by :func:`os.process_cpu_count` is used.
27792783

27802784
If *initializer* is not ``None`` then each worker process will call
27812785
``initializer(*initargs)`` when it starts.

Doc/whatsnew/3.13.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ Other Language Changes
9191
of the ``optimize`` argument.
9292
(Contributed by Irit Katriel in :gh:`108113`).
9393

94+
* :mod:`multiprocessing`, :mod:`concurrent.futures`, :mod:`compileall`:
95+
Replace :func:`os.cpu_count` with :func:`os.process_cpu_count` to select the
96+
default number of worker threads and processes. Get the CPU affinity
97+
if supported.
98+
(Contributed by Victor Stinner in :gh:`109649`.)
99+
100+
94101
New Modules
95102
===========
96103

Lib/concurrent/futures/process.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ def __init__(self, max_workers=None, mp_context=None,
666666
_check_system_limits()
667667

668668
if max_workers is None:
669-
self._max_workers = os.cpu_count() or 1
669+
self._max_workers = os.process_cpu_count() or 1
670670
if sys.platform == 'win32':
671671
self._max_workers = min(_MAX_WINDOWS_WORKERS,
672672
self._max_workers)

Lib/concurrent/futures/thread.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ def __init__(self, max_workers=None, thread_name_prefix='',
139139
# * CPU bound task which releases GIL
140140
# * I/O bound task (which releases GIL, of course)
141141
#
142-
# We use cpu_count + 4 for both types of tasks.
142+
# We use process_cpu_count + 4 for both types of tasks.
143143
# But we limit it to 32 to avoid consuming surprisingly large resource
144144
# on many core machine.
145-
max_workers = min(32, (os.cpu_count() or 1) + 4)
145+
max_workers = min(32, (os.process_cpu_count() or 1) + 4)
146146
if max_workers <= 0:
147147
raise ValueError("max_workers must be greater than 0")
148148

Lib/multiprocessing/pool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def __init__(self, processes=None, initializer=None, initargs=(),
200200
self._initargs = initargs
201201

202202
if processes is None:
203-
processes = os.cpu_count() or 1
203+
processes = os.process_cpu_count() or 1
204204
if processes < 1:
205205
raise ValueError("Number of processes must be at least 1")
206206
if maxtasksperchild is not None:

Lib/test/libregrtest/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
426426
if self.num_workers < 0:
427427
# Use all CPUs + 2 extra worker processes for tests
428428
# that like to sleep
429-
self.num_workers = (os.cpu_count() or 1) + 2
429+
self.num_workers = (os.process_cpu_count() or 1) + 2
430430

431431
# For a partial run, we do not need to clutter the output.
432432
if (self.want_header

Lib/test/libregrtest/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,9 @@ def display_header(use_resources: tuple[str, ...],
546546

547547
cpu_count = os.cpu_count()
548548
if cpu_count:
549+
process_cpu_count = os.process_cpu_count()
550+
if process_cpu_count and process_cpu_count != cpu_count:
551+
cpu_count = f"{process_cpu_count} (process) / {cpu_count} (system)"
549552
print("== CPU count:", cpu_count)
550553
print("== encodings: locale=%s, FS=%s"
551554
% (locale.getencoding(), sys.getfilesystemencoding()))

Lib/test/pythoninfo.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ def format_attr(attr, value):
239239
'getresgid',
240240
'getresuid',
241241
'getuid',
242+
'process_cpu_count',
242243
'uname',
243244
):
244245
call_func(info_add, 'os.%s' % func, os, func)

Lib/test/test_concurrent_futures/test_thread_pool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def record_finished(n):
2525

2626
def test_default_workers(self):
2727
executor = self.executor_type()
28-
expected = min(32, (os.cpu_count() or 1) + 4)
28+
expected = min(32, (os.process_cpu_count() or 1) + 4)
2929
self.assertEqual(executor._max_workers, expected)
3030

3131
def test_saturation(self):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:mod:`multiprocessing`, :mod:`concurrent.futures`, :mod:`compileall`:
2+
Replace :func:`os.cpu_count` with :func:`os.process_cpu_count` to select the
3+
default number of worker threads and processes. Get the CPU affinity if
4+
supported. Patch by Victor Stinner.

Modules/_decimal/tests/deccheck.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ def tfunc():
13011301
out, _ = p.communicate()
13021302
write_output(out, p.returncode)
13031303

1304-
N = os.cpu_count()
1304+
N = os.process_cpu_count()
13051305
t = N * [None]
13061306

13071307
for i in range(N):

Tools/freeze/test/freeze.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def prepare(script=None, outdir=None):
130130
if not MAKE:
131131
raise UnsupportedError('make')
132132

133-
cores = os.cpu_count()
133+
cores = os.process_cpu_count()
134134
if cores and cores >= 3:
135135
# this test is most often run as part of the whole suite with a lot
136136
# of other tests running in parallel, from 1-2 vCPU systems up to

Tools/ssl/multissltests.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ class AbstractBuilder(object):
151151
build_template = None
152152
depend_target = None
153153
install_target = 'install'
154-
jobs = os.cpu_count()
154+
if hasattr(os, 'process_cpu_count'):
155+
jobs = os.process_cpu_count()
156+
else:
157+
jobs = os.cpu_count()
155158

156159
module_files = (
157160
os.path.join(PYTHONROOT, "Modules/_ssl.c"),

Tools/wasm/wasm_build.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,11 @@ def make_cmd(self) -> List[str]:
516516
def getenv(self) -> Dict[str, Any]:
517517
"""Generate environ dict for platform"""
518518
env = os.environ.copy()
519-
env.setdefault("MAKEFLAGS", f"-j{os.cpu_count()}")
519+
if hasattr(os, 'process_cpu_count'):
520+
cpu_count = os.process_cpu_count()
521+
else:
522+
cpu_count = os.cpu_count()
523+
env.setdefault("MAKEFLAGS", f"-j{cpu_count}")
520524
platenv = self.host.platform.getenv(self)
521525
for key, value in platenv.items():
522526
if value is None:

0 commit comments

Comments
 (0)