[Python-checkins] cpython: Issue #27664: Add to concurrent.futures.thread.ThreadPoolExecutor()

gregory.p.smith python-checkins at python.org
Sun Aug 7 13:19:28 EDT 2016


https://hg.python.org/cpython/rev/1002a1bdc5b1
changeset:   102561:1002a1bdc5b1
user:        Gregory P. Smith <greg at krypto.org>
date:        Sun Aug 07 10:19:20 2016 -0700
summary:
  Issue #27664: Add to concurrent.futures.thread.ThreadPoolExecutor()
the ability to specify a thread name prefix.

files:
  Doc/library/concurrent.futures.rst  |   6 +++-
  Lib/concurrent/futures/thread.py    |  11 +++++--
  Lib/test/test_concurrent_futures.py |  24 +++++++++++++++++
  Misc/NEWS                           |   3 ++
  4 files changed, 40 insertions(+), 4 deletions(-)


diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst
--- a/Doc/library/concurrent.futures.rst
+++ b/Doc/library/concurrent.futures.rst
@@ -124,7 +124,7 @@
    executor.submit(wait_on_future)
 
 
-.. class:: ThreadPoolExecutor(max_workers=None)
+.. class:: ThreadPoolExecutor(max_workers=None, thread_name_prefix='')
 
    An :class:`Executor` subclass that uses a pool of at most *max_workers*
    threads to execute calls asynchronously.
@@ -137,6 +137,10 @@
       should be higher than the number of workers
       for :class:`ProcessPoolExecutor`.
 
+   .. versionadded:: 3.6
+      The *thread_name_prefix* argument was added to allow users to
+      control the threading.Thread names for worker threads created by
+      the pool for easier debugging.
 
 .. _threadpoolexecutor-example:
 
diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py
--- a/Lib/concurrent/futures/thread.py
+++ b/Lib/concurrent/futures/thread.py
@@ -81,12 +81,13 @@
         _base.LOGGER.critical('Exception in worker', exc_info=True)
 
 class ThreadPoolExecutor(_base.Executor):
-    def __init__(self, max_workers=None):
+    def __init__(self, max_workers=None, thread_name_prefix=''):
         """Initializes a new ThreadPoolExecutor instance.
 
         Args:
             max_workers: The maximum number of threads that can be used to
                 execute the given calls.
+            thread_name_prefix: An optional name prefix to give our threads.
         """
         if max_workers is None:
             # Use this number because ThreadPoolExecutor is often
@@ -100,6 +101,7 @@
         self._threads = set()
         self._shutdown = False
         self._shutdown_lock = threading.Lock()
+        self._thread_name_prefix = thread_name_prefix
 
     def submit(self, fn, *args, **kwargs):
         with self._shutdown_lock:
@@ -121,8 +123,11 @@
             q.put(None)
         # TODO(bquinlan): Should avoid creating new threads if there are more
         # idle threads than items in the work queue.
-        if len(self._threads) < self._max_workers:
-            t = threading.Thread(target=_worker,
+        num_threads = len(self._threads)
+        if num_threads < self._max_workers:
+            thread_name = '%s_%d' % (self._thread_name_prefix or self,
+                                     num_threads)
+            t = threading.Thread(name=thread_name, target=_worker,
                                  args=(weakref.ref(self, weakref_cb),
                                        self._work_queue))
             t.daemon = True
diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py
--- a/Lib/test/test_concurrent_futures.py
+++ b/Lib/test/test_concurrent_futures.py
@@ -154,6 +154,30 @@
         for t in threads:
             t.join()
 
+    def test_thread_names_assigned(self):
+        executor = futures.ThreadPoolExecutor(
+            max_workers=5, thread_name_prefix='SpecialPool')
+        executor.map(abs, range(-5, 5))
+        threads = executor._threads
+        del executor
+
+        for t in threads:
+            self.assertRegex(t.name, r'^SpecialPool_[0-4]$')
+            t.join()
+
+    def test_thread_names_default(self):
+        executor = futures.ThreadPoolExecutor(max_workers=5)
+        executor.map(abs, range(-5, 5))
+        threads = executor._threads
+        del executor
+
+        for t in threads:
+            # We don't particularly care what the default name is, just that
+            # it has a default name implying that it is a ThreadPoolExecutor
+            # followed by what looks like a thread number.
+            self.assertRegex(t.name, r'^.*ThreadPoolExecutor.*_[0-4]$')
+            t.join()
+
 
 class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest, unittest.TestCase):
     def _prime_executor(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -43,6 +43,9 @@
 Library
 -------
 
+- Issue #27664: Add to concurrent.futures.thread.ThreadPoolExecutor()
+  the ability to specify a thread name prefix.
+
 - Issue #26750: unittest.mock.create_autospec() now works properly for
   subclasses of property() and other data descriptors.  Removes the never
   publicly used, never documented unittest.mock.DescriptorTypes tuple.

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list