Python多线程和Python的锁Python多线程Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版
Python多线程和Python的锁
Python多线程
Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于threading模块的Thread类。
其实Python的多线程编程不能真正利用多核的CPU,但是用开源模块使你的计算压力分布到多核CPU上.........
一.使用start_new_thread()实现线程,是比较底层的实现方式,所有线程共享他们global数据,为了达到同步,模块也提供了简单的锁机制
import _threadimport timedef threadFunction(count): for i in range(count): print('进程id为%d的打印%d'%(_thread.get_ident(),i)) i-=1 time.sleep(0.1)def begin(): ident1=_thread.start_new_thread(threadFunction,(100,)) print('启动标识符为%d的进程'%(ident1,)) ident2=_thread.start_new_thread(threadFunction,(100,)) print('启动标识符为%d的进程'%(ident2,)) if __name__ == '__main__': begin()
二.使用Thread类来实现多线程,这种方式是对_thread模块(如果没有_thread,则为dummy_threading)的高级封装,在这种方式下我们需创建新类继承threading.Thread,和java一样重写threading.Thread的run方法即可.启动线程用线程的start方法,它会调用我们重写的run方法.
class MyThread(threading.Thread): '''只能重写__init__ 和 run 两个方法''' def __init__(self,name): threading.Thread.__init__(self) self.name=name self.bool_stop=False def run(self): while not self.bool_stop: print('进程%s,于%s'%(self.name,time.asctime())) time.sleep(1) def stop(self): self.bool_stop = Trueif __name__ == '__main__': th1=MyThread('one') th2=MyThread('two') th1.start() th2.start()
Thread类还定义了以下常用方法与属性:
import _thread,time,randomdish=0lock = _thread.allocate_lock()def producerFunction(): '''如果投的筛子比0.2大,则向盘子中增加一个苹果''' global lock,dish while True: if(random.random() > 0.1): lock.acquire() if dish < 100: dish+=1 print('生产者增加了一个苹果,现在有%d个苹果'%(dish,)) lock.release() time.sleep(random.random()*3)def consumerFunction(): '''如果投的筛子比0.5大,则从盘子中取一个苹果''' global lock,dish while True: if(random.random() > 0.9): lock.acquire() if dish > 0: dish-=1 print('消费者拿走一个苹果现,在有%d个苹果'%(dish,)) lock.release() time.sleep(random.random()*3)def begin(): ident1=_thread.start_new_thread(producerFunction,()) ident2=_thread.start_new_thread(consumerFunction,()) if __name__ == '__main__': begin()
另一个较高级的锁为RLock锁,RLock对象内部维护着一个Lock对象,它是一种可重入的对象。对于Lock对象而言,如果一个线程连续两次进行acquire操作,那么由于第一次acquire之后没有release,第二次acquire将挂起线程。这会导致Lock对象永远不会release,使得线程死锁。RLock对象允许一个线程多次对其进行acquire操作,因为在其内部通过一个counter变量维护着线程acquire的次数。而且每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。
threading模块对Lock也提供和封装,提供了更高级的同步方式(可以理解为更高级的锁),包括threading.Event和threading.Condition,其中threading.Event为提供了简单的同步方式:一个进程标记event,其他进程等待,只需下面的几个方法即可:
Event.wait([timeout])堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。Event.set()将标识号设为TureEvent.clear()设为标识符False
threading.Condition 可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):
Condition.wait([timeout]): wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。Condition.notify(): 唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。Condition.notify_all() 唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。