多线程的使用
上篇文章并发 Vs 并行-CSDN博客,讲述了并发和并行的区别,并讲述了多进程库multiprocessing的使用过程和注意事项。
本篇讲解Python中实现并行的效果的库threading的使用。
1. 线程一定会加快速度吗?
线程是一个独立的执行过程,通过线程可以实现同时运行多个任务。但是对于大多数Python实现,不同的线程并不是同时执行,它们只是看起来同时执行。
很容易认为线程就像在程序中运行两个(或多个)不同的处理器,每个处理器同时执行一个独立的任务。这差不多是对的。线程可能在不同的处理器上运行,但它们每次只能运行一个。
要同时运行多个任务,需要采用非标准的 Python 实现方式、用其他语言编写部分代码,或者使用multiprocessing处理,但这会带来一些额外的开销。
由于 CPython 实现 Python 的方式,多线程可能无法加快所有任务的速度。这是由于与全局解释器锁(GIL)的交互,实际上限制了同一时间只有一个 Python 线程在运行。
那些大部分时间都处于等待外部事件状态的任务通常非常适合采用多线程技术。而那些需要大量 CPU 计算且等待外部事件的时间很少的任务,可能根本不会因此而运行得更快。
2. 使用threading
Python标准库threading可以帮助我们实现线程的控制和使用。
2.1 创建线程并启动
通过threading.Thread实例对象表示一个线程,并通过其start方法启动线程。
Thread中参数说明:
- target参数表示该线程执行的函数
- args参数为一个元组,表示传入线程任务中的实参
import threading
import timedef task(name):print(f"线程 {name} :start")time.sleep(2)print(f"线程 {name} :end")if __name__ == "__main__":print("主线程: 创建子线程前")t = threading.Thread(target=task, args=(1,))print("主线程: 子线程启动前")t.start()print("主线程: 等待子线程完成")print("主线程: 结束")
通过上述代码的运行可以看到主线程结束后,子线程依旧在执行。整个程序在子线程结束后才结束。
2.2 守护线程
在计算机科学中,守护进程运行在后台。当程序结束时,守护线程会理解关闭。
如果程序运行非守护线程的线程,那么程序将等待这些线程完成后再终止。但是,守护进程线程无论位于何处,在程序退出时都会被终止。
当你的 Python 程序结束时,关闭过程的一部分是清理线程例程。
import threading
import timedef task(name):print(f"线程 {name} :start")time.sleep(2)print(f"线程 {name} :end")if __name__ == "__main__":print("主线程: 创建子线程前")t = threading.Thread(target=task, args=(1,), daemon=True)print("主线程: 子线程启动前")t.start()print("主线程: 等待子线程完成")print("主线程: 结束")
通过设置Thread中的daemon参数为True,可以设置线程为守护线程。这样守护线程就会随着主线程结束而结束,而不会等待守护线程任务的结束。
2.3 线程的join方法
当希望主线程等待子线程结束后,再继续执行时,需要在子线程中调用join方法。
import threading
import timedef task(name):p