本文以实例形式较为详细的讲解了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,多线程,教程
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新动态
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]