多线程:在同一个时间做多件事
守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行。
thread.join():在子线程完成运行之前,该子线程的父线程(一般就是主线程)将一直存在,也就是被阻塞
线程池原理
线程池基本原理: 我们把任务放进队列中去,然后开N个线程,每个线程都去队列中取一个任务,执行完了之后告诉系统说我执行完了,然后接着去队列中取下一个任务,直至队列中所有任务取空,退出线程。
上面这个例子生成一个有3个线程的线程池,每个线程都无限循环阻塞读取Queue队列的任务所有任务都只会让这3个预生成的线程来处理。
具体工作描述如下:
创建Queue.Queue()实例,然后对它填充数据或任务
生成守护线程池,把线程设置成了daemon守护线程
每个线程无限循环阻塞读取queue队列的项目item,并处理
每次完成一次工作后,使用queue.task_done()函数向任务已经完成的队列发送一个信号
主线程设置queue.join()阻塞,直到任务队列已经清空了,解除阻塞,向下执行
这个模式下有几个注意的点:
将线程池的线程设置成daemon守护进程,意味着主线程退出时,守护线程也会自动退出,如果使用默认
daemon=False的话, 非daemon的线程会阻塞主线程的退出,所以即使queue队列的任务已经完成
线程池依然阻塞无限循环等待任务,使得主线程也不会退出。
当主线程使用了queue.join()的时候,说明主线程会阻塞直到queue已经是清空的,而主线程怎么知道queue已经是清空的呢?就是通过每次线程queue.get()后并处理任务后,发送queue.task_done()信号,queue的数据就会减1,直到queue的数据是空的,queue.join()解除阻塞,向下执行。
这个模式主要是以队列queue的任务来做主导的,做完任务就退出,由于线程池是daemon的,所以主退出线程池所有线程都会退出。 有别于我们平时可能以队列主导thread.join()阻塞,这种线程完成之前阻塞主线程。看需求使用哪个join():
如果是想做完一定数量任务的队列就结束,使用queue.join(),比如爬取指定数量的网页
如果是想线程做完任务就结束,使用thread.join()
import time import queue import threading queue = queue.Queue() # 定义需要线程池执行的任务 def do_job(): while True: i = queue.get() time.sleep(1) print(i, threading.current_thread()) queue.task_done() if __name__ == '__main__': # 创建包括3个线程的线程池 time.sleep(3) for i in range(10): queue.put(i) for i in range(3): t = threading.Thread(target=do_job) t.daemon = True # 设置线程daemon 主线程退出,daemon线程也会推出,即时正在运行 t.start() # 模拟创建线程池3秒后塞进10个任务到队列 queue.join()