threading --- 執行緒層級的平行處理

原始碼:Lib/threading.py


此模組在較低層的 _thread 模組之上,建構了較高層的執行緒(threading)介面。

可用性: not WASI.

此模組在 WebAssembly 平台上不起作用或無法使用。更多資訊請參閱 WebAssembly 平台

介紹

模組 threading 提供了一種方式,能在單一進程(process)中同時執行多個 執行緒 (一個進程中的較小執行單元)。它允許創造與管理執行緒,使多個任務可以平行執行並共享同一個記憶體空間。當任務屬於 I/O 密集型(I/O bound)時,執行緒特別有用,例如檔案操作或網路請求,因為這類任務的大部分時間都花在等待外部資源。

模組 threading 的一個典型使用情境是管理一個工作執行緒(worker threads)池,讓多個任務能夠同時被處理。以下是一個使用 Thread: 來創造並啟動執行緒的基本範例:

import threading
import time

def crawl(link, delay=3):
    print(f"crawl started for {link}")
    time.sleep(delay)  # Blocking I/O (simulating a network request)
    print(f"crawl ended for {link}")

links = [
    "https://python.org",
    "https://docs.python.org",
    "https://peps.python.org",
]

# Start threads for each link
threads = []
for link in links:
    # Using `args` to pass positional arguments and `kwargs` for keyword arguments
    t = threading.Thread(target=crawl, args=(link,), kwargs={"delay": 2})
    threads.append(t)

# Start each thread
for t in threads:
    t.start()

# Wait for all threads to finish
for t in threads:
    t.join()

在 3.7 版的變更: This module used to be optional, it is now always available.

也參考

concurrent.futures.ThreadPoolExecutor offers a higher level interface to push tasks to a background thread without blocking execution of the calling thread, while still being able to retrieve their results when needed.

queue provides a thread-safe interface for exchanging data between running threads.

asyncio offers an alternative approach to achieving task level concurrency without requiring the use of multiple operating system threads.

備註

In the Python 2.x series, this module contained camelCase names for some methods and functions. These are deprecated as of Python 3.10, but they are still supported for compatibility with Python 2.5 and lower.

CPython 實作細節: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing or concurrent.futures.ProcessPoolExecutor. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.

GIL and performance considerations

Unlike the multiprocessing module, which uses separate processes to bypass the global interpreter lock (GIL), the threading module operates within a single process, meaning that all threads share the same memory space. However, the GIL limits the performance gains of threading when it comes to CPU-bound tasks, as only one thread can execute Python bytecode at a time. Despite this, threads remain a useful tool for achieving concurrency in many scenarios.

As of Python 3.13, free-threaded builds can disable the GIL, enabling true parallel execution of threads, but this feature is not available by default (see PEP 703).

Reference

此模組定義了以下函式:

threading.active_count()

Return the number of Thread objects currently alive. The returned count is equal to the length of the list returned by enumerate().

The function activeCount is a deprecated alias for this function.

threading.current_thread()

Return the current Thread object, corresponding to the caller's thread of control. If the caller's thread of control was not created through the threading module, a dummy thread object with limited functionality is returned.

currentThread 函式是此函式的已棄用別名。

threading.excepthook(args, /)

處理由 Thread.run() 引發且未被捕捉到的例外。

args 引數有下列屬性:

  • exc_type:例外型別。

  • exc_value: Exception value, can be None.

  • exc_traceback: Exception traceback, can be None.

  • thread:引發例外的執行緒,可以是 None

If exc_type is SystemExit, the exception is silently ignored. Otherwise, the exception is printed out on sys.stderr.

如果這個函式引發例外,則會呼叫 sys.excepthook() 來處理它。

threading.excepthook() can be overridden to control how uncaught exceptions raised by Thread.run() are handled.

Storing exc_value using a custom hook can create a reference cycle. It should be cleared explicitly to break the reference cycle when the exception is no longer needed.

Storing thread using a custom hook can resurrect it if it is set to an object which is being finalized. Avoid storing thread after the custom hook completes to avoid resurrecting objects.

也參考

sys.excepthook() 處理未被捕捉到的例外。

在 3.8 版被加入.

threading.__excepthook__

Holds the original value of threading.excepthook(). It is saved so that the original value can be restored in case they happen to get replaced with broken or alternative objects.

在 3.10 版被加入.

threading.get_ident()

Return the 'thread identifier' of the current thread. This is a nonzero integer. Its value has no direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of thread-specific data. Thread identifiers may be recycled when a thread exits and another thread is created.

在 3.3 版被加入.

threading.get_native_id()

Return the native integral Thread ID of the current thread assigned by the kernel. This is a non-negative integer. Its value may be used to uniquely identify this particular thread system-wide (until the thread terminates, after which the value may be recycled by the OS).

可用性: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD, GNU/kFreeBSD.

在 3.8 版被加入.

在 3.13 版的變更: 新增對 GNU/kFreeBSD 的支援。

threading.enumerate()

Return a list of all Thread objects currently active. The list includes daemonic threads and dummy thread objects created by current_thread(). It excludes terminated threads and threads that have not yet been started. However, the main thread is always part of the result, even when terminated.

threading.main_thread()

Return the main Thread object. In normal conditions, the main thread is the thread from which the Python interpreter was started.

在 3.4 版被加入.

threading.settrace(func)

Set a trace function for all threads started from the threading module. The func will be passed to sys.settrace() for each thread, before its run() method is called.

threading.settrace_all_threads(func)

Set a trace function for all threads started from the threading module and all Python threads that are currently executing.

The func will be passed to sys.settrace() for each thread, before its run() method is called.

在 3.12 版被加入.

threading.gettrace()

Get the trace function as set by settrace().

在 3.10 版被加入.

threading.setprofile(func)

Set a profile function for all threads started from the threading module. The func will be passed to sys.setprofile() for each thread, before its run() method is called.

threading.setprofile_all_threads(func)

Set a profile function for all threads started from the threading module and all Python threads that are currently executing.

The func will be passed to sys.setprofile() for each thread, before its run() method is called.

在 3.12 版被加入.

threading.getprofile()

取得由 setprofile() 設定的剖析函式。

在 3.10 版被加入.

threading.stack_size([size])

Return the thread stack size used when creating new threads. The optional size argument specifies the stack size to be used for subsequently created threads, and must be 0 (use platform or configured default) or a positive integer value of at least 32,768 (32 KiB). If size is not specified, 0 is used. If changing the thread stack size is unsupported, a RuntimeError is raised. If the specified stack size is invalid, a ValueError is raised and the stack size is unmodified. 32 KiB is currently the minimum supported stack size value to guarantee sufficient stack space for the interpreter itself. Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32 KiB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4 KiB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific information).

可用性: Windows, pthreads.

Unix platforms with POSIX threads support.

此模組也定義了以下常數:

threading.TIMEOUT_MAX

The maximum value allowed for the timeout parameter of blocking functions (Lock.acquire(), RLock.acquire(), Condition.wait(), etc.). Specifying a timeout greater than this value will raise an OverflowError.

在 3.2 版被加入.

This module defines a number of classes, which are detailed in the sections below.

The design of this module is loosely based on Java's threading model. However, where Java makes locks and condition variables basic behavior of every object, they are separate objects in Python. Python's Thread class supports a subset of the behavior of Java's Thread class; currently, there are no priorities, no thread groups, and threads cannot be destroyed, stopped, suspended, resumed, or interrupted. The static methods of Java's Thread class, when implemented, are mapped to module-level functions.

All of the methods described below are executed atomically.

Thread-local data

Thread-local data is data whose values are thread specific. If you have data that you want to be local to a thread, create a local object and use its attributes:

>>> mydata = local()
>>> mydata.number = 42
>>> mydata.number
42

You can also access the local-object's dictionary:

>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

If we access the data in a different thread:

>>> log = []
>>> def f():
...     items = sorted(mydata.__dict__.items())
...     log.append(items)
...     mydata.number = 11
...     log.append(mydata.number)

>>> import threading
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[], 11]

we get different data. Furthermore, changes made in the other thread don't affect data seen in this thread:

>>> mydata.number
42

Of course, values you get from a local object, including their __dict__ attribute, are for whatever thread was current at the time the attribute was read. For that reason, you generally don't want to save these values across threads, as they apply only to the thread they came from.

You can create custom local objects by subclassing the local class:

>>> class MyLocal(local):
...     number = 2
...     def __init__(self, /, **kw):
...         self.__dict__.update(kw)
...     def squared(self):
...         return self.number ** 2

This can be useful to support default values, methods and initialization. Note that if you define an __init__() method, it will be called each time the local object is used in a separate thread. This is necessary to initialize each thread's dictionary.

現在如果我們建立一個 local 物件:

>>> mydata = MyLocal(color='red')

會有一個預設的數字:

>>> mydata.number
2

和一個初始顏色:

>>> mydata.color
'red'
>>> del mydata.color

和一個操作資料的方法:

>>> mydata.squared()
4

As before, we can access the data in a separate thread:

>>> log = []
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[('color', 'red')], 11]

without affecting this thread's data:

>>> mydata.number
2
>>> mydata.color
Traceback (most recent call last):
...
AttributeError: 'MyLocal' object has no attribute 'color'

Note that subclasses can define __slots__, but they are not thread local. They are shared across threads:

>>> class MyLocal(local):
...     __slots__ = 'number'

>>> mydata = MyLocal()
>>> mydata.number = 42
>>> mydata.color = 'red'

So, the separate thread:

>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()

affects what we see:

>>> mydata.number
11
class threading.local

A class that represents thread-local data.

Thread 物件

The Thread class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, only override the __init__() and run() methods of this class.

Once a thread object is created, its activity must be started by calling the thread's start() method. This invokes the run() method in a separate thread of control.

Once the thread's activity is started, the thread is considered 'alive'. It stops being alive when its run() method terminates -- either normally, or by raising an unhandled exception. The is_alive() method tests whether the thread is alive.

Other threads can call a thread's join() method. This blocks the calling thread until the thread whose join() method is called is terminated.

A thread has a name. The name can be passed to the constructor, and read or changed through the name attribute.

If the run() method raises an exception, threading.excepthook() is called to handle it. By default, threading.excepthook() ignores silently SystemExit.

A thread can be flagged as a "daemon thread". The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property or the daemon constructor argument.

備註

Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.

There is a "main thread" object; this corresponds to the initial thread of control in the Python program. It is not a daemon thread.

There is the possibility that "dummy thread objects" are created. These are thread objects corresponding to "alien threads", which are threads of control started outside the threading module, such as directly from C code. Dummy thread objects have limited functionality; they are always considered alive and daemonic, and cannot be joined. They are never deleted, since it is impossible to detect the termination of alien threads.

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None, context=None)

This constructor should always be called with keyword arguments. Arguments are:

group should be None; reserved for future extension when a ThreadGroup class is implemented.

target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.

name is the thread name. By default, a unique name is constructed of the form "Thread-N" where N is a small decimal number, or "Thread-N (target)" where "target" is target.__name__ if the target argument is specified.

args is a list or tuple of arguments for the target invocation. Defaults to ().

kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.

If not None, daemon explicitly sets whether the thread is daemonic. If None (the default), the daemonic property is inherited from the current thread.

context is the Context value to use when starting the thread. The default value is None which indicates that the sys.flags.thread_inherit_context flag controls the behaviour. If the flag is true, threads will start with a copy of the context of the caller of start(). If false, they will start with an empty context. To explicitly start with an empty context, pass a new instance of Context(). To explicitly start with a copy of the current context, pass the value from copy_context(). The flag defaults true on free-threaded builds and false otherwise.

If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.

在 3.3 版的變更: 新增 daemon 參數。

在 3.10 版的變更: Use the target name if name argument is omitted.

在 3.14 版的變更: 新增 context 參數。

start()

Start the thread's activity.

It must be called at most once per thread object. It arranges for the object's run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

If supported, set the operating system thread name to threading.Thread.name. The name can be truncated depending on the operating system thread name limits.

在 3.14 版的變更: Set the operating system thread name.

run()

Method representing the thread's activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object's constructor as the target argument, if any, with positional and keyword arguments taken from the args and kwargs arguments, respectively.

Using list or tuple as the args argument which passed to the Thread could achieve the same effect.

舉例來說:

>>> from threading import Thread
>>> t = Thread(target=print, args=[1])
>>> t.run()
1
>>> t = Thread(target=print, args=(1,))
>>> t.run()
1
join(timeout=None)

Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates -- either normally or through an unhandled exception -- or until the optional timeout occurs.

When the timeout argument is present and not None, it should be a floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened -- if the thread is still alive, the join() call timed out.

When the timeout argument is not present or None, the operation will block until the thread terminates.

A thread can be joined many times.

join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raise the same exception.

If an attempt is made to join a running daemonic thread in late stages of Python finalization join() raises a PythonFinalizationError.

在 3.14 版的變更: 可能引發 PythonFinalizationError

name

A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor.

On some platforms, the thread name is set at the operating system level when the thread starts, so that it is visible in task managers. This name may be truncated to fit in a system-specific limit (for example, 15 bytes on Linux or 63 bytes on macOS).

Changes to name are only reflected at the OS level when the currently running thread is renamed. (Setting the name attribute of a different thread only updates the Python Thread object.)

getName()
setName()

Deprecated getter/setter API for name; use it directly as a property instead.

在 3.10 版之後被棄用.

ident

The 'thread identifier' of this thread or None if the thread has not been started. This is a nonzero integer. See the get_ident() function. Thread identifiers may be recycled when a thread exits and another thread is created. The identifier is available even after the thread has exited.

native_id

The Thread ID (TID) of this thread, as assigned by the OS (kernel). This is a non-negative integer, or None if the thread has not been started. See the get_native_id() function. This value may be used to uniquely identify this particular thread system-wide (until the thread terminates, after which the value may be recycled by the OS).

備註

Similar to Process IDs, Thread IDs are only valid (guaranteed unique system-wide) from the time the thread is created until the thread has been terminated.

可用性: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD.

在 3.8 版被加入.

is_alive()

Return whether the thread is alive.

This method returns True just before the run() method starts until just after the run() method terminates. The module function enumerate() returns a list of all alive threads.

daemon

A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.

The entire Python program exits when no alive non-daemon threads are left.

isDaemon()
setDaemon()

Deprecated getter/setter API for daemon; use it directly as a property instead.

在 3.10 版之後被棄用.

Lock 物件

原語鎖 (primitive lock) 是一種同步原語 (synchronization primitive),在鎖定時不屬於特定執行緒。在 Python 中,它是目前可用的最低階同步原語,直接由 _thread 擴充模組實作。

原語鎖會處於兩種狀態之一:「鎖定 (locked)」或「未鎖定 (unclocked)」,建立時會處於未鎖定狀態。它有兩個基本方法 acquire()release()。當狀態為未鎖定時,acquire() 會將狀態變更為鎖定並立即回傳。當狀態被鎖定時,acquire() 會阻塞 (block),直到另一個執行緒中對 release() 的呼叫將其更改為未鎖定狀態,然後 acquire() 呼叫會將其重置為鎖定並回傳。release() 方法只能在鎖定狀態下呼叫;它將狀態更改為未鎖定並立即回傳。如果嘗試釋放未鎖定的鎖,則會引發 RuntimeError

鎖也支援情境管理協定

當多個執行緒阻塞在 acquire() 中等待狀態轉變為未鎖定,此時若呼叫 release() 將狀態重置為未鎖定,則只會有一個執行緒繼續進行;哪一個等待執行緒會繼續進行是未定義的,並且可能因實作而異。

所有方法均以最小不可分割的操作方式 (atomically) 執行。

class threading.Lock

實作原語鎖物件的類別。一旦執行緒獲得了鎖,後續再嘗試獲得它就會被阻塞,直到鎖被釋放;任何執行緒都可以去釋放它。

在 3.13 版的變更: Lock 現在是一個類別。在早期的 Python 中,Lock 是一個會回傳底層私有鎖型別實例的工廠函式。

acquire(blocking=True, timeout=-1)

阻塞或非阻塞地取得鎖。

當以 blocking 引數設為 True(預設值)來叫用,將會阻塞直到鎖被解鎖,然後將其設為鎖定並回傳 True

當以 blocking 引數設為 False 叫用則不會阻塞。如果 blocking 設定為 True 的呼叫會阻塞,則立即回傳 False;否則將鎖設為鎖定並回傳 True

當使用設定為正值的浮點 timeout 引數進行叫用,只要持續無法取得鎖,最多會阻塞 timeout 指定的秒數。-1timeout 引數代表指定為不會停止的等待。當 blockingFalse 時禁止指定 timeout

如果成功取得鎖,則回傳值為 True,否則回傳值為 False(例如像是 timeout 已逾期)。

在 3.2 版的變更: 新的 timeout 參數。

在 3.2 版的變更: 如果底層執行緒實作支援的話,鎖的取得現在可以被 POSIX 上的訊號中斷。

在 3.14 版的變更: Lock acquisition can now be interrupted by signals on Windows.

release()