如果想让我们的程序同时执行多个任务,就需要使用多线程技术了 。到目前为止,我们编写的程序都是单线程的,在运行时一次只能执行 一个任务。
1 线程相关的知识
1.1 进程
一个进程就是一个正在执行的程序,每一个进程都有自己独立的一 块内存空间、一组系统资源。在进程的概念中,每一个进程的内部数据 和状态都是完全独立的。
在Windows操作系统中,一个进程就是一个exe或者dll程序,它们 相互独立,相互也可以通信。
1.2 线程
在一个进程中可以包含多个线程,多个线程共享一块内存空间和一 组系统资源。所以,系统在各个线程之间切换时,开销要比进程小得多 ,正因如此,线程被称为轻量级进程。
1.3 主线程
Python程序至少有一个线程,这就是主线程,程序在启动后由Pytho n解释器负责创建主线程,在程序结束后由Python解释器负责停止主线 程。
在多线程中,主线程负责其他线程的启动、挂起、停止等操作。其 他线程被称为子线程。
2 线程模块——threading
Python官方提供的threading模块可以进行多线程编程。threading模 块提供了多线程编程的高级API,使用起来比较简单。
在threading模块中提供了线程类Thread,还提供了很多线程相关的 函数,这些函数中常用的如下。
active_count():返回当前处于活动状态的线程个数。
current_thread():返回当前的Thread对象。
main_thread():返回主线程对象。主线程是Python解释器启动的 线程。示例代码如下:
3 创建子线程
创建一个可执行的子线程,需要如下两个要素。
1 线程对象:线程对象是threading模块的线程类Thread或Thread子 类所创建的对象。
2 线程体:线程体是子线程要执行的代码,这些代码会被封装到一 个函数中。子线程在启动后会执行线程体。实现线程体主要有以下两种 方式。
1)自定义函数实现线程体。
2)自定义线程类实现线程体。
3.1 自定义函数实现线程体
创建线程Thread对象的构造方法如下:
target参数指向线程体函数,我们可以自定义该线程体函数;通过n ame参数可以设置线程名,如果省略这个参数,则系统会为其分配一个 名称;args是为线程体函数提供的参数,是一个元组类型。 示例代码如下:
3.2 自定义线程类实现线程体
另外一种实现线程体的方式是,创建一个Thread子类并重写run() 方法,run()方法就是线程体函数。
采用自定义线程类重新实现16.3.1节的示例,示例代码如下:
4 线程管理
线程管理包括线程创建、线程启动、线程休眠、等待线程结束和线 程停止,其中,线程创建、线程启动和线程休眠在3节已经用到了, 这些不再赘述。本节重点介绍等待线程结束和线程停止的内容。
4.1 等待线程结束
有时,一个线程(假设是主线程)需要等待另外一个线程(假设是 t1子线程)执行结束才能继续执行。
4.2 线程停止
在线程体结束时,线程就停止了。但在某些业务比较复杂时,会在 线程体中执行一个“死循环”。线程体是否持续执行“死循环”是通过判断 停止变量实现的,“死循环”结束则线程体结束,线程也就结束了。
另外,在一般情况下,死循环会执行线程任务,然后休眠,再执行 ,再休眠,直到结束循环。
通过Python指令运行文件:
5 动动手——下载图片示例
这个网络爬虫程序每隔一段时间都会执行一次下载图片任务,在下 载任务完成后,休眠一段时间再执行。这样反复执行,直到爬虫程序停 止。
示例参考代码如下:
本示例从服务器下载图片,因此需要参考14.2节启动Web服务器, 然后通过Python指令运行文件。
6 练一练
1 请简述如何创建线程体。
2 请简述线程中join()方法的作用。
3 下列哪些情况可以停止当前线程的运行?()
A.引发一个异常时。
B.当该线程调用sleep()方法时。
C.当创建一个新线程时。
D.当该线程调用stop()方法时。
4 判断对错(请在括号内打√或×,√表示正确,×表示错误)。
1)线程对象是threading模块线程类Thread或Thread子类所创建的对 象。()
2)实现线程体主要有以下两种方式:自定义函数实现线程体和自 定义线程类实现线程体。()
3)在线程体结束时,可通过调用stop()方法停止。()
4)在线程体结束时,可通过调用join()方法停止。()