Skip to content

Commit c0be80f

Browse files
committed
翻译12.1节
1 parent 62d71cb commit c0be80f

File tree

1 file changed

+122
-136
lines changed

1 file changed

+122
-136
lines changed

source/c12/p01_start_stop_thread.rst

Lines changed: 122 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -5,148 +5,134 @@
55
----------
66
问题
77
----------
8-
You want to create and destroy threads for concurrent execution of code.
9-
10-
|
8+
你要为需要并发执行的代码创建/销毁线程
119

1210
----------
1311
解决方案
1412
----------
15-
The threading library can be used to execute any Python callable in its own thread. To
16-
do this, you create a Thread instance and supply the callable that you wish to execute
17-
as a target. Here is a simple example:
18-
19-
# Code to execute in an independent thread
20-
import time
21-
def countdown(n):
22-
while n > 0:
23-
print('T-minus', n)
24-
n -= 1
25-
time.sleep(5)
26-
27-
# Create and launch a thread
28-
from threading import Thread
29-
t = Thread(target=countdown, args=(10,))
30-
t.start()
31-
32-
When you create a thread instance, it doesn’t start executing until you invoke its start()
33-
method (which invokes the target function with the arguments you supplied).
34-
Threads are executed in their own system-level thread (e.g., a POSIX thread or Windows
35-
threads) that is fully managed by the host operating system. Once started, threads run
36-
independently until the target function returns. You can query a thread instance to see
37-
if it’s still running:
38-
39-
if t.is_alive():
40-
print('Still running')
41-
else:
42-
print('Completed')
43-
44-
You can also request to join with a thread, which waits for it to terminate:
45-
46-
t.join()
47-
48-
The interpreter remains running until all threads terminate. For long-running threads
49-
or background tasks that run forever, you should consider making the thread daemonic.
50-
For example:
51-
52-
t = Thread(target=countdown, args=(10,), daemon=True)
53-
t.start()
54-
55-
Daemonic threads can’t be joined. However, they are destroyed automatically when the
56-
main thread terminates.
57-
Beyond the two operations shown, there aren’t many other things you can do with
58-
threads. For example, there are no operations to terminate a thread, signal a thread,
59-
adjust its scheduling, or perform any other high-level operations. If you want these
60-
features, you need to build them yourself.
61-
If you want to be able to terminate threads, the thread must be programmed to poll for
62-
exit at selected points. For example, you might put your thread in a class such as this:
63-
64-
class CountdownTask:
65-
def __init__(self):
66-
self._running = True
67-
68-
def terminate(self):
69-
self._running = False
70-
71-
def run(self, n):
72-
while self._running and n > 0:
73-
print('T-minus', n)
74-
n -= 1
75-
time.sleep(5)
76-
77-
c = CountdownTask()
78-
t = Thread(target=c.run, args=(10,))
79-
t.start()
80-
...
81-
c.terminate() # Signal termination
82-
t.join() # Wait for actual termination (if needed)
83-
84-
Polling for thread termination can be tricky to coordinate if threads perform blocking
85-
operations such as I/O. For example, a thread blocked indefinitely on an I/O operation
86-
may never return to check if it’s been killed. To correctly deal with this case, you’ll need
87-
to carefully program thread to utilize timeout loops. For example:
88-
89-
class IOTask:
90-
def terminate(self):
91-
self._running = False
92-
93-
def run(self, sock):
94-
# sock is a socket
95-
sock.settimeout(5) # Set timeout period
96-
while self._running:
97-
# Perform a blocking I/O operation w/ timeout
98-
try:
99-
data = sock.recv(8192)
100-
break
101-
except socket.timeout:
102-
continue
103-
# Continued processing
104-
...
105-
# Terminated
106-
return
107-
13+
``threading`` 库可以在单独的线程中执行任何的在 Python 中可以调用的对象。你可以创建一个 ``Thread`` 对象并将你要执行的对象以 target 参数的形式提供给该对象。
14+
下面是一个简单的例子:
15+
16+
.. code-block:: python
17+
18+
# Code to execute in an independent thread
19+
import time
20+
def countdown(n):
21+
while n > 0:
22+
print('T-minus', n)
23+
n -= 1
24+
time.sleep(5)
25+
26+
# Create and launch a thread
27+
from threading import Thread
28+
t = Thread(target=countdown, args=(10,))
29+
t.start()
30+
31+
当你创建好一个线程对象后,该对象并不会立即执行,除非你调用它的 ``start()`` 方法(当你调用 ``start()`` 方法时,它会调用你传递进来的函数,并把你传递进来的参数传递给该函数)。Python中的线程会在一个单独的系统级线程中执行(比如说一个 POSIX 线程或者一个 Windows 线程),这些线程将由操作系统来全权管理。线程一旦启动,将独立执行直到目标函数返回。你可以查询一个线程对象的状态,看它是否还在执行:
32+
33+
.. code-block:: python
34+
35+
if t.is_alive():
36+
print('Still running')
37+
else:
38+
print('Completed')
39+
40+
你也可以将一个线程加入到当前线程,并等待它终止:
41+
42+
.. code-block:: python
43+
44+
t.join()
45+
46+
Python解释器在所有线程都终止后才继续执行代码剩余的部分。对于需要长时间运行的线程或者需要一直运行的后台任务,你应当考虑使用后台线程。
47+
例如:
48+
49+
.. code-block:: python
50+
51+
t = Thread(target=countdown, args=(10,), daemon=True)
52+
t.start()
53+
54+
后台线程无法等待,不过,这些线程会在主线程终止时自动销毁。
55+
除了如上所示的两个操作,并没有太多可以对线程做的事情。你无法结束一个线程,无法给它发送信号,无法调整它的调度,也无法执行其他高级操作。如果需要这些特性,你需要自己添加。比如说,如果你需要终止线程,那么这个线程必须通过编程在某个特定点轮询来退出。你可以像下边这样把线程放入一个类中:
56+
57+
.. code-block:: python
58+
59+
class CountdownTask:
60+
def __init__(self):
61+
self._running = True
62+
63+
def terminate(self):
64+
self._running = False
65+
66+
def run(self, n):
67+
while self._running and n > 0:
68+
print('T-minus', n)
69+
n -= 1
70+
time.sleep(5)
71+
72+
c = CountdownTask()
73+
t = Thread(target=c.run, args=(10,))
74+
t.start()
75+
c.terminate() # Signal termination
76+
t.join() # Wait for actual termination (if needed)
77+
78+
如果线程执行一些像I/O这样的阻塞操作,那么通过轮询来终止线程将使得线程之间的协调变得非常棘手。比如,如果一个线程一直阻塞在一个I/O操作上,它就永远无法返回,也就无法检查自己是否已经被结束了。要正确处理这些问题,你需要利用超时循环来小心操作线程。
79+
例子如下:
80+
81+
.. code-block:: python
82+
83+
class IOTask:
84+
def terminate(self):
85+
self._running = False
86+
87+
def run(self, sock):
88+
# sock is a socket
89+
sock.settimeout(5) # Set timeout period
90+
while self._running:
91+
# Perform a blocking I/O operation w/ timeout
92+
try:
93+
data = sock.recv(8192)
94+
break
95+
except socket.timeout:
96+
continue
97+
# Continued processing
98+
...
99+
# Terminated
100+
return
108101
|
109102
110103
----------
111104
讨论
112105
----------
113-
Due to a global interpreter lock (GIL), Python threads are restricted to an execution
114-
model that only allows one thread to execute in the interpreter at any given time. For
115-
this reason, Python threads should generally not be used for computationally intensive
116-
tasks where you are trying to achieve parallelism on multiple CPUs. They are much
117-
better suited for I/O handling and handling concurrent execution in code that performs
118-
blocking operations (e.g., waiting for I/O, waiting for results from a database, etc.).
119-
Sometimes you will see threads defined via inheritance from the Thread class. For
120-
example:
121-
122-
from threading import Thread
123-
124-
class CountdownThread(Thread):
125-
def __init__(self, n):
126-
super().__init__()
127-
self.n = 0
128-
def run(self):
129-
while self.n > 0:
130-
131-
print('T-minus', self.n)
132-
self.n -= 1
133-
time.sleep(5)
134-
135-
c = CountdownThread(5)
136-
c.start()
137-
138-
Although this works, it introduces an extra dependency between the code and the
139-
threading library. That is, you can only use the resulting code in the context of threads,
140-
whereas the technique shown earlier involves writing code with no explicit dependency
141-
on threading. By freeing your code of such dependencies, it becomes usable in other
142-
contexts that may or may not involve threads. For instance, you might be able to execute
143-
your code in a separate process using the multiprocessing module using code like this:
144-
145-
import multiprocessing
146-
c = CountdownTask(5)
147-
p = multiprocessing.Process(target=c.run)
148-
p.start()
149-
...
150-
151-
Again, this only works if the CountdownTask class has been written in a manner that is
152-
neutral to the actual means of concurrency (threads, processes, etc.).
106+
由于全局解释锁(GIL)的原因,Python 的线程被限制到同一时刻只允许一个线程执行这样一个执行模型。所以,Python 的线程更适用于处理I/O和其他需要并发执行的阻塞操作(比如等待I/O、等待从数据库获取数据等等),而不是需要多处理器并行的计算密集型任务。
107+
108+
有时你会看到下边这种通过继承 ``Thread`` 类来实现的线程:
109+
110+
.. code-block:: python
111+
112+
from threading import Thread
113+
114+
class CountdownThread(Thread):
115+
def __init__(self, n):
116+
super().__init__()
117+
self.n = 0
118+
def run(self):
119+
while self.n > 0:
120+
121+
print('T-minus', self.n)
122+
self.n -= 1
123+
time.sleep(5)
124+
125+
c = CountdownThread(5)
126+
c.start()
127+
128+
尽管这样也可以工作,但这使得你的代码依赖于 ``threading`` 库,所以你的这些代码只能在线程上下文中使用。上文所写的那些代码、函数都是与 ``threading`` 库无关的,这样就使得这些代码可以被用在其他的上下文中,可能与线程有关,也可能与线程无关。比如,你可以通过 ``multiprocessing`` 模块在一个单独的进程中执行你的代码:
129+
130+
.. code-block:: python
131+
132+
import multiprocessing
133+
c = CountdownTask(5)
134+
p = multiprocessing.Process(target=c.run)
135+
p.start()
136+
137+
138+
再次重申,这段代码仅适用于 CountdownTask 类是以独立于实际的并发手段(多线程、多进程等等)实现的情况。

0 commit comments

Comments
 (0)