10.1 多线程的定义

10.1 多线程的定义

人们在日常生活中发现,如果一件事情同时让多个人一起做,那么它的完成速度比一个人单独做要快得多,特别是在生产线上,体现得更为明显。比如,要生产1000个零件,一台机器生产需要1小时,如果10台机器同时生产,那么生产时间可以缩小为原来的1/10。

在这里,一台机器生产零件的方式称为单线程或单进程。10台机器同时生产称为多线程或多进程。

多线程技术的引入并不仅是为了提高处理速度和硬件资源的利用率,更重要的是可以提高系统的可扩展性和用户体验。采用多线程技术编写的代码移植到多处理器平台上不需要改写,就能立刻适应新的平台。

虽然对于单核CPU计算机,使用多线程并不能提高任务完成速度,但有些场合必须要使用多线程技术,或采用多线程技术可以让整个系统的设计更加人性化。

【案例10-1】 对于一个.zip格式的压缩包,默认密码是6位数字。编写一个能暴力破解加密.zip文件的小程序。

暴力破解的基本思路是,调用Python中zipfile模块的trypassword函数,尝试从0到999999的所有数字,成功解压时即相应的压缩密码。

最直白粗暴的实现方法:先导入zipfile库,以利用遍历数字进行匹配的方式实现。如果密码是6位数字,则在000000~999999之间进行遍历,发现数字匹配时,则结束。

实现代码:

运行结果:

该案例用到zipfile的相关方法。

·zipfile.Zipfile(filename,'r'):创建压缩文件的对象,以只读方式打开。

·extractall(pwd=bytes(密码,'ascii')):进行密码匹配,给出参数pwd的值,需以字节流的方式,指明提供的密码是ascii码(utf-8)。

从程序代码中可以看出,在使用暴力破解的过程中,一直只有一个线程在工作,耗时比较长。

如果使用多个线程同时工作来匹配密码,会不会减少运行时间呢?

1.进程

接触过计算机的读者都使用过多种软件。例如,启动Word时,先用鼠标双击它的图标,Word软件将从硬盘读取到内存,并弹出Word窗口。这个正在内存中运行的Word程序就是一个进程。

通俗地说,进程就是在计算机内存中运行的一个软件,即一个应用程序在处理机上的一次执行过程,它是一个动态的概念。

进程是线程的容器,也就是说线程是进程中的一部分,进程包含多个线程在运行。

在Windows操作系统中,启动“任务管理器”,弹出的子窗口中有一个“进程”选项卡,在这里可看到该操作系统目前正在运行的各种进程,如图10-1所示。

图10-1 任务管理器中的进程

2.线程

磁盘上的应用程序文件被打开并执行时会创建一个进程,但是进程本身并不是执行单元,从来不执行任何东西,主要用作线程和相关资源的容器。要使进程中的代码真正运行起来,必须至少拥有一个能在这个环境中运行代码的执行单元,也就是线程。

线程有时被称为轻量级进程(Light Weight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID、当前指令指针、寄存器集合和堆栈组成。

线程是进程内的一个执行单元,也是进程内的可调度实体。线程是操作系统调度的基本单位,负责执行包含在进程地址空间中的代码并访问其中的资源。

当一个进程被创建时,操作系统自动为它创建一个线程,通常称为主线程。一个进程可以包含多个线程,主线程根据需要再动态地创建其他子线程。例如,利用“迅雷”下载资源时,发现它可以同步下载多个文件,这个下载过程就用到了多线程。

操作系统为每一个线程保存单独的寄存器环境和单独的堆栈,但是所有的子线程共享进程的地址空间、对象句柄、代码、数据和其他资源。

线程不能脱离进程而独立存在,但允许属于同一个进程的多个线程之间进行数据共享和同步控制。一般来说,除了主线程的生命周期与所属进程的生命周期一样之外,其他的子线程生命周期均小于所属进程的生命周期。

简而言之,一个程序至少有一个进程,一个进程至少有一个线程。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。

线程被创建之后,并不是始终保持着一种状态,可以分为如下几种状态。

·New:新建。新创建的线程经过初始化以后,进入就绪状态。

·Runnable:就绪。等待系统调度,被调度以后进入运行状态。

·Running:运行。

·Blocked:阻塞。解除阻塞以后,会进入就绪状态,重新等待调度。

·Dead:消亡。线程方法执行完毕,返回或者异常终止。

3.线程分类

线程可以分为以下几种类型。

·主线程。程序启动后,系统会创建并立刻运行一个线程,该线程称为程序的主线程(main thread)。

·子线程。在程序中创建的其他线程,相对主线程来说,就是它的子线程。

·守护线程。守护线程是运行在后台的一种特殊线程,故也称为后台线程。它独立于控制终端且周期性地执行某种任务或等待处理某些发生的事件。它的作用是为其他线程提供服务,譬如操作系统的垃圾回收站、打印服务等。守护线程的另一个特点是当主线程,如软件关闭时,守护线程会同步终止执行。这对退出前还需要处理部分数据保存等情况,是非常不利的。由此,退出主线程前,需要处理其他资源,建议使用守护线程方式。

·前台线程。相对守护线程的其他线程称为前台线程,应用程序的主线程以及使用Thread构造的线程都默认为前台线程。

前台线程和后台线程的区别在于:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。