基本的python多线程问题

时间:2012-07-23 21:00:08

标签: python multithreading thread-safety

python的新手并尝试理解多线程。这是来自Queue

的python文档的示例

对于我的生活,我不明白这个例子是如何运作的。在worker()函数中,存在无限循环。工人如何知道何时离开循环?似乎没有破坏条件。

最后连接究竟是做什么的?我不应该加入线程吗?

def worker():
    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(num_worker_threads):
    t = Thread(target=worker)
    t.daemon = True
    t.start()

for item in source():
    q.put(item)

q.join()       # block until all tasks are done

另外一个问题,何时应该使用多线程以及何时应该使用多处理?

3 个答案:

答案 0 :(得分:6)

烨。你是对的。 worker将永远运行。但是,由于Queue只有有限数量的项目,最终worker将永久阻塞q.get()(因为队列中不再有项目)。此时,worker仍然在运行,这是无关紧要的。 q.join()阻塞,直到队列计数降为0(每当工作线程调用q.task_done时,计数下降1)。之后,程序结束。无限阻塞的线程与它的创建者一起消失。

答案 1 :(得分:5)

关于你的第二个问题,Python中线程和进程之间的最大区别是主流实现使用全局解释器锁(GIL)来确保多个线程不会弄乱Python的内部数据结构。这意味着对于花费大部分时间在纯Python上进行计算的程序,即使使用多个CPU,也不会加快程序的速度,因为一次只有一个线程可以保存GIL。另一方面,多个线程可以在Python程序中轻松共享数据,在某些(但并非全部)情况下,您不必过于担心线程安全。

当多线程可以加速Python程序时,程序花费大部分时间等待I / O - 磁盘访问,或者特别是现在的网络操作。在执行I / O时不会保留GIL,因此许多Python线程可以在I / O绑定应用程序中并发运行。

另一方面,通过多处理,每个进程都有自己的GIL,因此您的性能可以扩展到可用的CPU核心数。缺点是进程之间的所有通信都必须通过multiprocessing.Queue完成(它在表面上非常像Queue.Queue,但具有非常不同的底层机制,因为它必须跨进程边界进行通信)。

由于通过线程安全或进程间队列工作可以避免很多潜在的线程问题,并且由于Python使它变得如此简单,multiprocessing模块非常有吸引力。

答案 2 :(得分:0)

同意joel-cornett,主要是。我试图在python2.7中运行以下代码片段:

from threading import Thread
from Queue import Queue

def worker():
    def do_work(item):
        print(item)

    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(4):
     t = Thread(target=worker)
     t.daemon = True
     t.start()

for item in range(10):
    q.put(item)

q.join()

输出结果为:

0
1
2
3
4
5
6
7
8
9
Exception in thread Thread-3 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/lib/python2.7/threading.py", line 504, in run
  File "abc.py", line 9, in worker
  File "/usr/lib/python2.7/Queue.py", line 168, in get
  File "/usr/lib/python2.7/threading.py", line 236, in wait
<type 'exceptions.TypeError'>: 'NoneType' object is not callable

我认为最可能的解释是:

当任务耗尽后队列变空,父线程从q.join()返回并退出队列后退出。子线程在收到“item = q.get()”中产生的第一个TypeError异常时终止,因为队列不再存在。