当前位置: 移动技术网 > IT编程>脚本编程>Python > Python多线程实例教程

Python多线程实例教程

2019年03月27日  | 移动技术网IT编程  | 我要评论

契约王妃 潇烟漠漠,余声图片,红红好姑娘歌词

本文以实例形式较为详细的讲解了python的多线程,是python程序设计中非常重要的知识点。分享给大家供大家参考之用。具体方法如下:

用过python的人都会觉得python的多线程很类似于java的多线程机制,但是比java的多线程更灵活。在早期的python多线程实现中,采用了thread模块。例如:  

from time import ctime,sleep 
from thread import start_new_thread 
def loop1(): 
  print "enter loop1:",ctime(); 
  sleep(3); 
  print "leave loop1:",ctime(); 
 
def loop2(): 
  print "enter loop2:",ctime(); 
  sleep(5); 
  print "leave loop2:",ctime(); 
 
def main(): 
  print "main begin:",ctime(); 
  start_new_thread(loop1, ()); 
  start_new_thread(loop2,()); 
  sleep(8); 
  print "main end:",ctime(); 
 
if __name__=="__main__": 
  main(); 

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

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

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

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

import thread; 
from time import sleep,ctime; 
from random import choice 
#the first param means the thread number 
#the second param means how long it sleep 
#the third param means the lock 
def loop(nloop,sec,lock): 
  print "thread ",nloop," start and will sleep ",sec; 
  sleep(sec); 
  print "thread ",nloop," end ",sec; 
  lock.release(); 
 
def main(): 
  seconds=[4,2]; 
  locks=[]; 
  for i in range(len(seconds)) : 
    lock=thread.allocate_lock(); 
    lock.acquire(); 
    locks.append(lock); 
     
  print "main thread begins:",ctime(); 
  for i,lock in enumerate(locks): 
    thread.start_new_thread(loop,(i,choice(seconds),lock)); 
  for lock in locks : 
    while lock.locked() :  
      pass; 
  print "main thread ends:",ctime(); 
 
if __name__=="__main__" : 
  main(); 

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

从以上介绍可以看出这个lock类非常类似于jdk5.0中的java.util.concurrent.locks.lock。不知道doug lea有没有参与这个模块的开发,只是比java中的lock类多了一个方法locked,用于检测lock对象是否还处于加锁的状态。

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

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

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

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

class thread(_verbose) : 
   __init__(self, group=none, target=none, name=none, args=(), kwargs=none, verbose=none) 

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

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

from time import ctime,sleep 
import threading; 
from random import choice 
 
def loop(number,sec): 
  print "thread ",number," begins and will sleep ",sec," at ",ctime(); 
  sleep(sec); 
  print "thread ",number,"ends at ",ctime(); 
   
def main(): 
  seconds=[2,4]; 
  threads=[]; 
  array=range(len(seconds)); 
  for i in array : 
    t=threading.thread(target=loop,args=(i,choice(seconds))); 
    threads.append(t); 
  print "main thread begins at ",ctime(); 
  for t in threads : 
    t.start(); 
  for t in threads : 
    t.join();     
  print "main thread ends at ",ctime(); 
 
if __name__=="__main__" : 
  main(); 
 

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

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

from time import ctime,sleep 
import threading; 
from random import choice 
 
class threadfunc(object): 
  def __init__(self,func,args,name): 
    self.func=func; 
    self.args=args; 
    self.name=name; 
     
  def __call__(self): 
    self.func(*self.args); 
 
def loop(number,sec): 
  print "thread ",number," begins and will sleep ",sec," at ",ctime(); 
  sleep(sec); 
  print "thread ",number,"ends at ",ctime(); 
   
def main(): 
  seconds=[2,4]; 
  threads=[]; 
  array=range(len(seconds)); 
  for i in array : 
    t=threading.thread(target=threadfunc(loop,(i,choice(seconds)),loop.__name__)); 
    threads.append(t); 
  print "main thread begins at ",ctime(); 
  for t in threads : 
    t.start(); 
  for t in threads : 
    t.join();     
  print "main thread ends at ",ctime(); 
 
if __name__=="__main__" : 
  main(); 

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

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

from time import ctime,sleep 
import threading; 
from random import choice 
 
class mythread(threading.thread): 
  def __init__(self,func,args,name): 
    super(mythread,self).__init__(); 
    self.func=func; 
    self.args=args; 
    self.name=name; 
       
  def run(self): 
    self.result=self.func(*self.args); 
 
  def getresult(self): 
    return self.result; 
   
def loop(number,sec): 
  print "thread ",number," begins and will sleep ",sec," at ",ctime(); 
  sleep(sec); 
  print "thread ",number,"ends at ",ctime(); 
   
def main(): 
  seconds=[2,4]; 
  threads=[]; 
  array=range(len(seconds)); 
  for i in array : 
    t=mythread(loop,(i,choice(seconds)),loop.__name__); 
    threads.append(t); 
  print "main thread begins at ",ctime(); 
  for t in threads : 
    t.start(); 
  for t in threads : 
    t.join();     
  print "main thread ends at ",ctime(); 
 
if __name__=="__main__" : 
  main(); 
  

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

希望本文所述对大家的python程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网