python多线程
2018年01月14日 22:02:28
阅读数:599
python3中支持多线程的目前有threading和Queue模块,之前的thread模块已经从最新的python3中移除,找不到。相比于以前的thread模块,threading模块更安全拥有更多的同步机制,可以提供更多的方法。
threading模块中支持守护线程,守护线程是一个等待客户端请求服务的服务器,如果没有客户端的请求,守护线程就是空闲的。若把一个守护线程设置为守护线程,那么这个线程就是不重要的,进程退出的时候不需要等待这线程执行完成。在主线程准备退出时候,不需要等待某些子线程完成,那么就可以把这些子线程设置为守护线程标记,为True表示该线程不重要,或者是该线程是为了等待客户端的请求而不做任何其他的事情。
在threading模块中我们主要使用thread类,thread类有很多的方法创建线程,主要有:
1.创建thread的实例,传递一个函数
2.创建thread的实例,传递一个可调用的类实例
3.派生thread的子类,并且创建子类的实例
(1)在单线程条件下:
[python] view plain copy
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Thu Jan 11 16:51:18 2018
- @author: lisir
- """
- from time import sleep
- from time import ctime
- def loop0():
- print('start loop 0 at :', ctime())
- sleep(4)
- print('loop 0 done at :', ctime())
- def loop1():
- print('start loop 1 at :', ctime())
- sleep(2)
- print('loop 1 done at :', ctime())
- def main():
- print('starting at: ', ctime())
- loop0()
- loop1()
- print('all done at :', ctime())
- if __name__ == '__main__':
- main()
(2)创建thread的实例,传递一个函数
[python] view plain copy
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Thu Jan 11 16:51:18 2018
- @author: lisir
- """
- import threading
- from time import sleep
- from time import ctime
- loops = [4, 2]
- def loop(nloop, nsec):
- print('start loop :', nloop, ' at: ', ctime())
- sleep(nsec)
- print('loop ', nloop, ' done at : ', ctime())
- def main():
- print('starting at: ', ctime())
- threads = []
- nloops = range(len(loops))
- for i in nloops:
- t = threading.Thread(target=loop,args=(i, loops[i]))
- threads.append(t)
- # start threads
- for i in nloops:
- threads[i].start()
- # wait for all threads to finish
- for i in nloops:
- threads[i].join()
- print('all done at :', ctime())
- if __name__ == '__main__':
- main()
此时的总体程序执行时间受限于“木桶效应”。总体时间相比单线程减少2s,总体时间决定于最长的哪个线程执行时间。实例化thread对象的时候,把函数target和参数args传递进去,然后返回thread的实例。在这里,实例化thread和调用thread.start_new_thread()的最大区别在于新的线程并不会立即去执行,在我们不希望线程立即执行的时候非常有用。当所有的线程都分配完成后,通过调用每个线程的start()函数让他们启动,在此之前他们不能执行。join()方法等待线程结束,或者是提供了超时;join()方法在我们需要等待线程完成的时候才有用。
(3)创建thread的实例,传递一个可调用的类实例
这个方法中创建一个ThreadFunc类,其构造函数设定该类的函数参数,函数自身,函数名字符串。当实例化thread类对象时,调用类ThreadFunc,此时就回去调用__call__()这个方法,我们已经有要用到的参数,所以不需要将其传递给thread()的构造函数,直接调用即可。
(4)派生thread的子类,并且创建子类的实例
[python] view plain copy
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Thu Jan 11 16:51:18 2018
- @author: lisir
- """
- import threading
- from time import sleep
- from time import ctime
- loops = [4, 2]
- class MyThread(threading.Thread):
- def __init__(self, func, args, name=''):
- threading.Thread.__init__(self)
- self.name = name
- self.func = func
- self.args = args
- def run(self):
- self.func(*self.args)
- def loop(nloop, nsec):
- print('start loop :', nloop, ' at: ', ctime())
- sleep(nsec)
- print('loop ', nloop, ' done at : ', ctime())
- def main():
- print('starting at: ', ctime())
- threads = []
- nloops = range(len(loops))
- for i in nloops:
- t = MyThread(loop, (i, loops[i]), loop.__name__)
- threads.append(t)
- # start threads
- for i in nloops:
- threads[i].start()
- # wait for all threads to finish
- for i in nloops:
- threads[i].join()
- print('all done at :', ctime())
- if __name__ == '__main__':
- main()
这个方法的改写中,MyThread子类构造函数必须调用基类的构造函数,同时之前的__call__()方法变成run()。
综合以上的方法练习一个单线程和多线程执行对比程序:
首先我们吧上面的第4个方法写成一个模块myThread.py的程序,在接下来的程序中去调用
myThread.py
[python] view plain copy
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Thu Jan 11 16:51:18 2018
- @author: lisir
- """
- # myThread.py
- import threading
- from time import sleep
- from time import ctime
- loops = [4, 2]
- class MyThread(threading.Thread):
- def __init__(self, func, args, name=''):
- threading.Thread.__init__(self)
- self.name = name
- self.func = func
- self.args = args
- def getResult(self):
- return self.res
- def run(self):
- print('starting ', self.name, ' at ', ctime())
- self.res = self.func(*self.args)
- print(self.name, ' done at ', ctime())
执行程序:
[python] view plain copy
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Thu Jan 11 16:51:18 2018
- @author: lisir
- """
- from myThread import MyThread
- from time import sleep
- from time import ctime
- def fib(x):
- sleep(0.005)
- if x < 2:
- return 1
- return (fib(x-2) + fib(x-1))
- def fac(x):
- sleep(0.1)
- if x < 2:
- return 1
- return (x * fac(x-1))
- def sum(x):
- sleep(0.1)
- if x < 2:
- return 1
- return (x + sum(x-1))
- funcs = [fib, fac, sum]
- n =12
- def main():
- nfuncs = range(len(funcs))
- print('starting at :', ctime())
- print("*********single thread***********")
- for i in nfuncs:
- print('starting ', funcs[i].__name__, 'at:',ctime())
- print(funcs[i](n))
- print(funcs[i].__name__, 'finish at :', ctime())
- print("*********multiple thread***********")
- threads = []
- for i in nfuncs:
- t = MyThread(funcs[i], (n,), funcs[i].__name__)
- threads.append(t)
- for i in nfuncs:
- threads[i].start()
- for i in nfuncs:
- threads[i].join()
- print(threads[i].getResult())
- print('all done at :', ctime())
- if __name__ == '__main__':
- main()
单线程模式下,简单的调用函数,执行函数结束就立即显示相应的结果。而多线程模式下并没有立即显示结果,在调用MyThread类后,等待所有线程都执行结束,然后去调用getResult()方法最终显示结果;这些函数的执行速度很快,因此这里加入sleep()函数减慢执行的速度。