Python多线程实例教程

作者:shichen2014 时间:2022-11-30 14:15:43 

本文以实例形式较为详细的讲解了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程序设计有所帮助。

标签:Python,多线程
0
投稿

猜你喜欢

  • 简单的python后台管理程序

    2022-01-07 03:49:30
  • Python虚拟环境virtualenv的安装与使用详解

    2022-02-22 02:19:46
  • 基于JS实现移动端向左滑动出现删除按钮功能

    2024-04-17 09:51:07
  • python3.7将代码打包成exe程序并添加图标的方法

    2021-01-17 08:29:32
  • JS实现动态添加外部js、css到head标签的方法

    2024-05-02 16:29:45
  • Python数据分析之NumPy常用函数使用详解

    2021-09-29 06:17:33
  • 详解Django中的form库的使用

    2022-05-16 00:13:50
  • python pandas中索引函数loc和iloc的区别分析

    2021-08-31 21:44:21
  • 如何进行MySQL数据库表的故障检测

    2009-02-10 10:34:00
  • MySql COALESCE函数使用方法代码案例

    2024-01-14 03:47:25
  • 有效的提高编程技能的12个方法

    2023-07-15 09:11:40
  • 跟我学习javascript的基本类型和引用类型

    2024-04-28 09:46:42
  • 使用python实现下拉选择框和页签的方法

    2021-10-01 04:07:41
  • Python变量和数据类型详解

    2022-01-25 07:26:25
  • 设计的俗化特征

    2010-04-08 16:07:00
  • 分享最新Sublime Text4 Build 4107注册码(密钥)汉化及完美永久破解方法

    2022-12-17 10:24:53
  • 浅析python 内置字符串处理函数的使用方法

    2021-07-17 09:23:09
  • python Django中models进行模糊查询的示例

    2023-08-02 05:54:09
  • django的分页器Paginator 从django中导入类

    2022-02-07 04:24:29
  • Persits AspJpeg组件图片水印\\缩略图\\图片合并\\图片切割\\实例教程

    2008-12-14 10:36:00
  • asp之家 网络编程 m.aspxhome.com