Python多线程实践
笔者以前测试过两个案例,都涉及到多线程的运用。特别是第二个ping功能,运用队列queue来完成数据交互。今天就来总结一下Python多线程。
一、python的多线程
python的全局解释器锁(GIL)会限制并发,在任意时刻只有一个线程在处理python代码。程序是cpu密集型的额,多线程无法提升程序的执行效率,如果程序是IO密集型的,多线程可以提高整个程序的下效率。
python的多线程使用标准库的threading的Thread类。
二、python的多线程测试
下面三个程序。第一个是循环调用函数say_hi,第二个是5个多线程执行say_hi,第三个是say_hi函数延时1秒钟。
来看一下各个程序的执行时间。第一个和第二个程序的执行时间差不多,第三个程序在say_hi函数延时1秒钟后的时间只有1.031秒。如果程序是cpu密集型,那么使用多线程的意义不大,反而会因为开启多线程而影响效率。
三、线程传递参数
在python中线程传递参数十分简单, 通过threading.Thread类调用args参数传递,所有参数 都是通过元组的形式传递。
三、继承线程
通过继承threading.Thread类来重定义多线程,需要在子类中实现run方法即可。新类MyThread重新定义构造函数__init__ ,并使用父类的构造函数__init__,在构造函数__init__中添加成员变量count和name。
关于继承的更多知识,请参考文章-Python面向对象实践。
四、线程同步与互斥锁
多个线程存在资源共享,对于每次只能一个线程操作数据,可以将操作放在acquire和release中。
也可以使用上下文管理器来直接的方便的管理锁资源。
下面的案例是多线程操作全局变量num,如果不使用互斥锁,那么计算出来的结果每次都不一样。在使用时,需要thread.join()来阻塞调用,直到线程终止,不然在线程有结束前,就会print过早的结果。
五、线程安全队列queue
笔者使用Shell和Python实现网络ping功能 来做说明。读取文件,将文件中的每一行入队列,再多线程的调用函数is_reacheable来非阻塞式的出队列完成ping功能,在队列为空时,退出循环。
我们可以查看标准库中queue.py的源码中的含义具体定义。里面定义了三个队列:Queue(先进先出队列)、LifoQueue(后进先出队列)、PriorityQueue(优先级队列)。使用的最多的就是先进先出队列。
再来看一下官方给的如何等待排队的任务被完成的示例。
task_done()表示前面排队的任务已经被完成。被队列的消费者线程使用。每个get()被用于获取一个任务, 后续调用 task_done()告诉队列,该任务的处理已经完成。join()阻塞至队列中所有的元素都被接收和处理完毕。