如果说Python的简单易用奠定了其发展的基石,那么丰富的第三方类库给予了Python不断前进发展的动力。随着科技的发展,Python应用得更为丰富,更多涉及不同种类的第三方类库被加入到Python之中。
Python常用类库的名称及其说明参见表1.1。
表1.1 Python常用类库
到目前为止,Python中已经有7000多个类库供计算机工程人员以及科学研究人员使用。
对于希望充分利用计算机性能的程序设计者来说,多线程的应用是必不可少的一个技能。多线程类似于使用计算机的一个核心执行多个不同任务。多线程的好处如下:
● 使用线程可以把需要使用大量时间的计算任务放到后台去处理。
● 减少资源占用,加快程序的运行速度。
● 在传统的输入输出以及网络收发等普通操作上,后台处理可以美化当前界面,增加界面的人性化。
本节将详细介绍Python中操作线程的模块——threading,相对于Python既有的多线程模块thread,threading重写了部分API模块,对thread进行了二次封装,从而大大提高了执行效率。重写了更方便的API来处理线程。
Thread是threading模块中最重要的类之一,可以使用它来创建线程。具体使用方法是创建一个threading.Thread对象,在它的初始化函数中将需要调用的对象作为初始化参数传入,具体代码如程序1-2所示。
# coding = utf8 import threading,time count = 0 class MyThread(threading.Thread): def __init__(self,threadName): super(MyThread,self).__init__(name = threadName) def run(self): global count for i in range(100): count = count + 1 time.sleep(0.3) print(self.getName() , count) for i in range(2): MyThread("MyThreadName:" + str(i)).start()
在上面代码定义的MyThread类中,重写了从父对象继承的run方法;在run方法中,将一个全局变量的值逐次加1;在接下来的代码中,创建了2个独立的对象,分别调用了其start方法,最后逐一打印结果。
可以看到,程序中每个线程被赋予了一个名字,然后设置每隔0.3秒打印输出本线程的计数,即计数加1。而count被设置成全局共享变量,因此在每个线程中都可以自由地对其进行访问。
程序运行结果如图1.16所示。
从上面的结果可以看到,每个线程被起了一个对应的名字,而在运行时,线程所计算的计数被同时增加,这样可以证明,在程序运行过程中两个线程同时对一个数进行操作,并打印其结果。
提示: 程序中的run方法和start方法,并不是threading自带的方法,而是从Python本身的线程处理模块Thread中继承来的。run方法的作用是在线程启动以后,执行预先写入的程序代码。一般而言,run方法所执行的内容被称为Activity。而start方法是用于启动线程。
图1.16
虽然线程可以在程序的执行过程中极大地提高程序的运行效率,但是其带来的影响却难以忽略。例如,在【程序1-2】中,每隔一定时间打印当前的数值,应该逐次打印的数据却变成了2个相同的数值被打印了出来,因此需要一个能够解决这类问题的方案。
Lock类是threading中用于锁定当前线程的锁定类,顾名思义,其作用是对当前运行中的线程进行锁定,被锁定的对象只有被当前线程释放后,才能由后续线程继续操作。类中主要代码如下:
import threading lock = threading.Lock() lock.acquire() lock.release()
acquire方法提供了确定对象被锁定的标志,release用于当前线程使用完对象后释放当前对象。修改后的代码如程序1-3所示。
# coding = utf8 import threading,time,random count = 0 class MyThread (threading.Thread): def __init__(self,lock,threadName): super(MyThread,self).__init__(name = threadName) self.lock = lock def run(self): global count self.lock.acquire() for i in range(100): count = count + 1 time.sleep(0.3) print(self.getName() , count) self.lock.release() lock = threading.Lock() for i in range(2): MyThread (lock,"MyThreadName:" + str(i)).start()
Lock被传递给MyThread,并在run方法中锁定当前的线程,必须等线程执行完毕后,后续的线程才可以继续执行。
程序执行结果如图1.17所示。从图中可以看到,其中框住的部分,线程2只有等线程1完全结束后,才执行后续的操作,即在本程序中,myThreadName:1等到myThreadName:0完全结束后,才执行后续操作。
图1.17
Join类是threading中用于堵塞当前主线程的类,其作用是阻止全部的线程继续运行,直到被调用的线程执行完毕或者超时。具体代码如程序1-4所示。
import threading, time def doWaiting(): print('start waiting:', time.strftime('%S')) time.sleep(3) print('stop waiting', time.strftime('%S')) thread1 = threading.Thread(target = doWaiting) thread1.start() time.sleep(1) # 确保线程thread1已经启动 print('start join') thread1.join() # 将一直堵塞,直到thread1运行结束 print('end join')
其中的time方法设定了当前的时间,当join启动后,堵塞了调用整体进程的主进程,而只有当被调用的进程执行完毕后,后续的进程才能继续执行。
程序的运行结果如图1.18所示。
图1.18
除此之外,对于线程的使用,Python还有很多其他方法,例如threading.Event、threading.Condition等,这些方法都能够极大地帮助程序设计人员编写合适的程序。限于篇幅这里不再展开介绍,在后续的讲解过程中,我们会带领读者掌握更多的相关内容。