Skip to content

Commit edd53ea

Browse files
committed
gh-156131: threading: add run() and run_daemon() to start threads easily
1 parent 7a845ce commit edd53ea

4 files changed

Lines changed: 43 additions & 1 deletion

File tree

Doc/library/threading.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@ This module defines the following functions:
220220
.. versionadded:: 3.4
221221

222222

223+
.. function:: run(func, /, *args, **kwargs)
224+
run_daemon(func, /, *args, **kwargs)
225+
226+
Run `func(*args, **kwargs)` in a thread and return the corresponding
227+
:class:`Thread` object. The thread is started automatically.
228+
229+
With :func:`run_daemon` the thread is set as daemonic.
230+
231+
.. versionadded:: 3.16
232+
233+
223234
.. function:: settrace(func)
224235

225236
.. index:: single: trace function

Lib/test/test_threading.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,21 @@ def run_in_bg():
15191519
self.assertEqual(err, b"")
15201520
self.assertEqual(out.strip(), b"Exiting...")
15211521

1522+
def test_run(self):
1523+
def func(x, y):
1524+
z.append(x + y)
1525+
1526+
z = []
1527+
thread = threading.run(func, 5, y=3)
1528+
thread.join()
1529+
self.assertEqual(z, [8])
1530+
1531+
z = []
1532+
thread = threading.run_daemon(func, 8, y=4)
1533+
thread.join()
1534+
self.assertEqual(z, [12])
1535+
self.assertEqual(thread.daemon, True)
1536+
15221537
class ThreadJoinOnShutdown(BaseTestCase):
15231538

15241539
def _run_and_join(self, script):

Lib/threading.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
'setprofile', 'settrace', 'local', 'stack_size',
3131
'excepthook', 'ExceptHookArgs', 'gettrace', 'getprofile',
3232
'serialize_iterator', 'synchronized_iterator', 'concurrent_tee',
33-
'setprofile_all_threads','settrace_all_threads']
33+
'setprofile_all_threads','settrace_all_threads',
34+
'run', 'run_daemon']
3435

3536
# Rename some stuff so "from threading import *" is safe
3637
_start_joinable_thread = _thread.start_joinable_thread
@@ -1664,6 +1665,19 @@ def enumerate():
16641665
with _active_limbo_lock:
16651666
return list(_active.values()) + list(_limbo.values())
16661667

1668+
def run(func, /, *args, **kwargs):
1669+
"""Return a running Thread object of func(*args, **kwargs)."""
1670+
thread = Thread(target=func, name=func.__name__, args=args, kwargs=kwargs)
1671+
thread.start()
1672+
return thread
1673+
1674+
def run_daemon(func, /, *args, **kwargs):
1675+
"""Return a running daemonic Thread object of func(*args, **kwargs)."""
1676+
thread = Thread(target=func, name=func.__name__, args=args, kwargs=kwargs)
1677+
thread.daemon = True
1678+
thread.start()
1679+
return thread
1680+
16671681

16681682
_threading_atexits = []
16691683
_SHUTTING_DOWN = False
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :func:`threading.run` and :func:`threading.run_daemon` functions as
2+
a convenient way to start threads.

0 commit comments

Comments
 (0)