python多线程

       python3中支持多线程的目前有threading和Queue模块,之前的thread模块已经从最新的python3中移除,找不到。相比于以前的thread模块,threading模块更安全拥有更多的同步机制,可以提供更多的方法。

       threading模块中支持守护线程,守护线程是一个等待客户端请求服务的服务器,如果没有客户端的请求,守护线程就是空闲的。若把一个守护线程设置为守护线程,那么这个线程就是不重要的,进程退出的时候不需要等待这线程执行完成。在主线程准备退出时候,不需要等待某些子线程完成,那么就可以把这些子线程设置为守护线程标记,为True表示该线程不重要,或者是该线程是为了等待客户端的请求而不做任何其他的事情。

       在threading模块中我们主要使用thread类,thread类有很多的方法创建线程,主要有:

1.创建thread的实例,传递一个函数

2.创建thread的实例,传递一个可调用的类实例

3.派生thread的子类,并且创建子类的实例

(1)在单线程条件下:

#!/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的实例,传递一个函数

#!/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的子类,并且创建子类的实例

#!/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

#!/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())
        
执行程序:

#!/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()函数减慢执行的速度。

你可能感兴趣的:(python)