Commit 9a7e5b1b authored by Inada Naoki's avatar Inada Naoki Committed by GitHub

bpo-35279: reduce default max_workers of ThreadPoolExecutor (GH-13618)

parent 293e9f86
...@@ -159,6 +159,15 @@ And:: ...@@ -159,6 +159,15 @@ And::
.. versionchanged:: 3.7 .. versionchanged:: 3.7
Added the *initializer* and *initargs* arguments. Added the *initializer* and *initargs* arguments.
.. versionchanged:: 3.8
Default value of *max_workers* is changed to ``min(32, os.cpu_count() + 4)``.
This default value preserves at least 5 workers for I/O bound tasks.
It utilizes at most 32 CPU cores for CPU bound tasks which release the GIL.
And it avoids using very large resources implicitly on many-core machines.
ThreadPoolExecutor now reuses idle worker threads before starting
*max_workers* worker threads too.
.. _threadpoolexecutor-example: .. _threadpoolexecutor-example:
......
...@@ -129,9 +129,14 @@ class ThreadPoolExecutor(_base.Executor): ...@@ -129,9 +129,14 @@ class ThreadPoolExecutor(_base.Executor):
initargs: A tuple of arguments to pass to the initializer. initargs: A tuple of arguments to pass to the initializer.
""" """
if max_workers is None: if max_workers is None:
# Use this number because ThreadPoolExecutor is often # ThreadPoolExecutor is often used to:
# used to overlap I/O instead of CPU work. # * CPU bound task which releases GIL
max_workers = (os.cpu_count() or 1) * 5 # * I/O bound task (which releases GIL, of course)
#
# We use cpu_count + 4 for both types of tasks.
# But we limit it to 32 to avoid consuming surprisingly large resource
# on many core machine.
max_workers = min(32, (os.cpu_count() or 1) + 4)
if max_workers <= 0: if max_workers <= 0:
raise ValueError("max_workers must be greater than 0") raise ValueError("max_workers must be greater than 0")
......
...@@ -755,8 +755,8 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase): ...@@ -755,8 +755,8 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase):
def test_default_workers(self): def test_default_workers(self):
executor = self.executor_type() executor = self.executor_type()
self.assertEqual(executor._max_workers, expected = min(32, (os.cpu_count() or 1) + 4)
(os.cpu_count() or 1) * 5) self.assertEqual(executor._max_workers, expected)
def test_saturation(self): def test_saturation(self):
executor = self.executor_type(4) executor = self.executor_type(4)
......
Change default *max_workers* of ``ThreadPoolExecutor`` from ``cpu_count() *
5`` to ``min(32, cpu_count() + 4))``. Previous value was unreasonably
large on many cores machines.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment