zoukankan      html  css  js  c++  java
  • 【跟我一起学Python吧】Python 多线程

     其实自我感觉Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活。在早期的Python多线程实现中,采用了thread模块。例如:   

       

    Python代码  收藏代码
    1. from time import ctime,sleep  
    2. from thread import start_new_thread  
    3. def loop1():  
    4.     print "enter loop1:",ctime();  
    5.     sleep(3);  
    6.     print "leave loop1:",ctime();  
    7.   
    8. def loop2():  
    9.     print "enter loop2:",ctime();  
    10.     sleep(5);  
    11.     print "leave loop2:",ctime();  
    12.   
    13. def main():  
    14.     print "main begin:",ctime();  
    15.     start_new_thread(loop1, ());  
    16.     start_new_thread(loop2,());  
    17.     sleep(8);  
    18.     print "main end:",ctime();  
    19.   
    20. if __name__=="__main__":  
    21.     main();  

        简单介绍下这个代码块中的函数功能,sleep是线程睡眠时间,几乎等价于JAVA中的Thread.sleep(millionseconds)

        start_new_thread是实例化一个线程并运行的方法,方法的第一个参数接受一个线程运行时所执行的函数对象,第二个参数是方法执行时所需要的参数,以一个元组的形式传入。   

        这大概是最早期的Python多线程实现了,注意代码中的main线程里的sleep(8)。这里的睡眠时间只能比3+5大,而不能小。如果小于这个时间,那么main主线程会提前退出,导致无论其子线程是否是后台线程,都将会中断,从而抛出线程中断异常,类似于Java的ThreadInterruptException。这个致命的影响几乎就是这个模块后期被抛弃的罪魁祸首。

        当然在早期的Python多线程中,你可以利用加锁的机制来避免出现这个情况。稍微改动下以上代码:

        

    Python代码  收藏代码
    1. import thread;  
    2. from time import sleep,ctime;  
    3. from random import choice  
    4. #The first param means the thread number  
    5. #The second param means how long it sleep  
    6. #The third param means the Lock  
    7. def loop(nloop,sec,lock):  
    8.     print "Thread ",nloop," start and will sleep ",sec;  
    9.     sleep(sec);  
    10.     print "Thread ",nloop," end  ",sec;  
    11.     lock.release();  
    12.   
    13. def main():  
    14.     seconds=[4,2];  
    15.     locks=[];  
    16.     for i in range(len(seconds)) :  
    17.         lock=thread.allocate_lock();  
    18.         lock.acquire();  
    19.         locks.append(lock);  
    20.           
    21.     print "main Thread begins:",ctime();  
    22.     for i,lock in enumerate(locks):  
    23.         thread.start_new_thread(loop,(i,choice(seconds),lock));  
    24.     for lock in locks :  
    25.         while lock.locked() :   
    26.             pass;  
    27.     print "main Thread ends:",ctime();  
    28.   
    29. if __name__=="__main__" :  
    30.     main();  

        这里对Python线程运行时加入了锁监控机制,介绍下红色字体标志的几个方法(其实红色字体中的lock实质是thread.lockType实例。 ):

        从以上介绍可以看出这个Lock类非常类似于JDK5.0中的java.util.concurrent.locks.Lock。不知道Doug Lea有没有参与这个模块的开发,哈哈~~(纯属YY),只是比JAVA中的LOCK类多了一个方法locked,用于检测Lock对象是否还处于加锁的状态。

        所以上一个例子的工作原理就是在启动线程的时候,给每个线程都加了一把锁,直到线程运行介绍,再释放这个锁。同时在Python的main线程中用一个while循环来不停的判断每个线程锁已释放。这个方法虽然避免了最开始的例子中人为的时间控制,但是还不方便,高效。

        所以在较新的Python版本中,都推荐使用threading模块。

        看下threading模块的API,有过JAVA开发经验的会发现它和java.lang.Thread类非常接近。这里需要说的一点就是threading的run方法可以返回函数值,这点在用于跟踪和判断线程运行正常与否非常有作用。

       threading模块支持三种方法来创建线程。而前两种方式都与其Thread类有关。看下它的简要说明:

        

    Python代码  收藏代码
    1. class Thread(_Verbose) :  
    2.      __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)  

       其中target指的是一个具体的函数,或者可调用的类实例(这里指实现了__call__方法的类实例) 

      第一种方法:指定线程运行的时候调用的函数。举例如下:

    Python代码  收藏代码
    1. from time import ctime,sleep  
    2. import threading;  
    3. from random import choice  
    4.   
    5. def loop(number,sec):  
    6.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
    7.     sleep(sec);  
    8.     print "Thread ",number,"ends at ",ctime();  
    9.       
    10. def main():  
    11.     seconds=[2,4];  
    12.     threads=[];  
    13.     array=range(len(seconds));  
    14.     for i in array :  
    15.         t=threading.Thread(target=loop,args=(i,choice(seconds)));  
    16.         threads.append(t);  
    17.     print "main Thread begins at ",ctime();  
    18.     for t in threads :  
    19.         t.start();  
    20.     for t in threads :  
    21.         t.join();          
    22.     print "main Thread ends at ",ctime();  
    23.   
    24. if __name__=="__main__" :  
    25.     main();  

        从图上可以看出,这里target指向了一个具体的函数对象,而args传入了该方法调用时所必须的参数。这里传入了一个随即的睡眠时间。其中thread.join表示要等待该线程终止,和java中的Thread.join(long millionseconds)作用一样,如果不指定具体的时间的话,将会一直等待下去。

       

       第二种方法就是指定一个可调用的类实例,实际上与前面一种非常的接近。如下所示:

      

    Python代码  收藏代码
    1. from time import ctime,sleep  
    2. import threading;  
    3. from random import choice  
    4.   
    5. class ThreadFunc(object):  
    6.     def __init__(self,func,args,name):  
    7.         self.func=func;  
    8.         self.args=args;  
    9.         self.name=name;  
    10.           
    11.     def __call__(self):  
    12.         self.func(*self.args);  
    13.   
    14. def loop(number,sec):  
    15.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
    16.     sleep(sec);  
    17.     print "Thread ",number,"ends at ",ctime();  
    18.       
    19. def main():  
    20.     seconds=[2,4];  
    21.     threads=[];  
    22.     array=range(len(seconds));  
    23.     for i in array :  
    24.         t=threading.Thread(target=ThreadFunc(loop,(i,choice(seconds)),loop.__name__));  
    25.         threads.append(t);  
    26.     print "main Thread begins at ",ctime();  
    27.     for t in threads :  
    28.         t.start();  
    29.     for t in threads :  
    30.         t.join();          
    31.     print "main Thread ends at ",ctime();  
    32.   
    33. if __name__=="__main__" :  
    34.     main();  

       这里只是将target指向从一个函数对象变成了一个可调用的类实例。

        重点推荐下第三种方式,用继承threading.Thread的方式来实现线程,有过Java多线程应用的朋友一定会对下面的例子非常熟悉。

       

    Python代码  收藏代码
    1. from time import ctime,sleep  
    2. import threading;  
    3. from random import choice  
    4.   
    5. class MyThread(threading.Thread):  
    6.     def __init__(self,func,args,name):  
    7.         super(MyThread,self).__init__();  
    8.         self.func=func;  
    9.         self.args=args;  
    10.         self.name=name;  
    11.               
    12.     def run(self):  
    13.         self.result=self.func(*self.args);  
    14.   
    15.     def getResult(self):  
    16.         return self.result;  
    17.       
    18. def loop(number,sec):  
    19.     print "Thread ",number," begins and will sleep ",sec," at ",ctime();  
    20.     sleep(sec);  
    21.     print "Thread ",number,"ends at ",ctime();  
    22.       
    23. def main():  
    24.     seconds=[2,4];  
    25.     threads=[];  
    26.     array=range(len(seconds));  
    27.     for i in array :  
    28.         t=MyThread(loop,(i,choice(seconds)),loop.__name__);  
    29.         threads.append(t);  
    30.     print "main Thread begins at ",ctime();  
    31.     for t in threads :  
    32.         t.start();  
    33.     for t in threads :  
    34.         t.join();          
    35.     print "main Thread ends at ",ctime();  
    36.   
    37. if __name__=="__main__" :  
    38.     main();  

        

        从上面可以看出MyThread继承了threading.Thread类,并在初始化方法中执行了必要的参数赋值。值得注意的是在Java类的继承中,如果不显示的指定调用父类的构造方法,那么默认将调用父类的无参构造方法。而在Python中,就不会主动去调用。所以这里需要显示的调用父类的初始化方法。

    推荐一个网站:程序人生

  • 相关阅读:
    mysql 表的类型
    【Mysql优化】key和index区别
    [置顶] 步步辨析JS中的对象成员
    [置顶] C语言单元测试框架
    代码规范总结
    AFNetworking、MKNetworkKit和ASIHTTPRequest对比
    在SQL中使用PL/SQL函数存在的问题
    C++中一个函数隐藏的有趣例子
    深入浅出Mybatis-分页
    SRM 207 Div II Level Two: RegularSeason,字符串操作(sstream),多关键字排序(操作符重载)
  • 原文地址:https://www.cnblogs.com/rrxc/p/3955280.html
Copyright © 2011-2022 走看看