TensorFlow深度学习应用实践
上QQ阅读APP看书,第一时间看更新

2.2 Python常用类库中的threading

如果说Python的简单易用奠定了Python的发展,那么丰富的第三方类库就是Python不断前进的动力。随着科技前沿的发展,Python应用越来越丰富,更多涉及不同种类的第三方类库被加入Python之中。

Python常用类库可参见表2-1。

表2-1 Python常用类库

表2-1给出了Python中常用类库的名称和说明。到目前为止,Python中已经有7000多个可以使用的类库供计算机工程人员以及科学研究人员使用。

2.2.1 threading库的使用

对于希望充分利用计算机性能的程序设计者来说,多线程的应用是必不可少的一个重要技能。多线程类似于使用计算机的一个核心执行多个不同任务。多线程的好处如下:

  • 使用线程可以把需要使用大量时间的计算任务放到后台去处理。
  • 减少资源占用,加快程序的运行速度。
  • 在传统的输入输出以及网络收发等普通操作上,后台处理可以美化当前界面,增加界面的人性化。

本节将详细介绍Python中操作线程的模块:threading。相对于Python既有的多线程模块thread,threading重写了部分API模块,对thread进行了二次封装,从而大大提高了执行效率;并且重写了更为方便的API来处理线程。

2.2.2 threading模块中最重要的Thread类

Thread是threading模块中的重要类之一,可以使用它来创造线程。其具体使用方法是创建一个threading.Thread对象,在它的初始化函数中将需要调用的对象作为初始化参数传入,具体代码如程序2-1所示。

【程序2-1】

在笔者定义的MyThread类中,重写了从父对象继承的run方法。在run方法中,将一个全局变量逐一增加,在接下来的代码中,创建了5个独立的对象,分别调用其start方法,最后将结果逐一打印。

在程序中,每个线程被赋予了一个名字,然后设置每隔0.3秒打印输出本线程的计数,即计数加1。而count被人为地设置成全局共享变量,因此在每个线程中都可以自由地对其进行访问。

程序运行结果如图2-16所示。

图2-16 程序运行结果

通过上面的结果可以看出,每个线程被起了一个对应的名字,而在运行的时候,线程所计算的计数被同时增加。这样可以证明,在程序运行过程中两个线程同时对一个数进行操作,并将其结果进行打印。

提示

其中的run方法和start方法并不是threading自带的方法,而是从Python本身的线程处理模块Thread中继承来的。run方法的作用是在线程被启动以后执行预先写入的程序代码。一般而言,run方法所执行的内容被称为Activity;而start方法是用于启动线程的方法。

2.2.3 threading中的Lock类

虽然线程可以在程序的执行过程中提高程序的运行效率,但是其带来的影响却难以忽略。例如,在上一个程序中,每隔一定时间就要打印当前的数值,应该逐次打印的数据却变成了两个相同的数值,因此需要一个能够解决这类问题的方案出现。

Lock类是threading中用于锁定当前线程的锁定类。顾名思义,其作用是对当前运行中的线程进行锁定,只有当前线程被释放后,后续线程才可以继续操作。

类中的主要代码如上所示。acquire方法提供了确定对象被锁定的标志,release在对象被当前线程使用完毕后将当前对象释放。修改后的代码如程序2-2所示。

【程序2-2】

Lock被传递给MyThread,并在run方法中人为锁定当前的线程,必须等线程执行完毕后,后续的线程才可以继续执行。程序执行结果如图2-17所示。

图2-17 程序运行结果

从变色的部分可以看出,线程2只有等线程1完全结束后才执行后续的操作。在本程序中,Thread1等到Thread0完全结束后才执行第二个操作。

2.2.4 threading中的join类

join类是threading中用于堵塞当前主线程的类,其作用是阻止全部的线程继续运行,直到被调用的线程执行完毕或者超时。具体代码如程序2-3所示。

【程序2-3】

程序的运行结果如图2-18所示。

图2-18 程序运行结果

其中的time方法设定了当前的时间。当join启动后,堵塞了调用整体进程的主进程,只有当被堵塞的进程执行完毕后,后续的进程才可以继续执行。

除此之外,对于线程的使用,Python还有很多其他的方法,例如threading.Event以及threading.Condition等。这些都是在程序设计时能够极大地帮助程序设计人员编写合适程序的工具。限于篇幅,这里不再一一进行介绍。在后续的使用过程中,笔者会带领读者了解和掌握更多的相关内容。