zoukankan      html  css  js  c++  java
  • Python多线程和Python的锁

    Python多线程 
    Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于threading模块的Thread类。 
    其实Python的多线程编程不能真正利用多核的CPU,但是用开源模块使你的计算压力分布到多核CPU上......... 

    一.使用start_new_thread()实现线程,是比较底层的实现方式,所有线程共享他们global数据,为了达到同步,模块也提供了简单的锁机制 

    _thread.start_new_thread(function, args[, kwargs])
    启动一个新的进程,并返回其标识符. 线程执行的函数需要的参数由args(必须为一个元组)提供,亦可通过可选参数kwargs提供关键字参数组  成的字典。当函数返回时,启动的线程也   停止退出。如果函数中存在未处理异常,会打印堆栈跟踪后线程停止退出(其他线程继续执行)。


    其中线程标识符是一个非0整数,并没有直接意思,可以当作从一个线程组成的特殊字典中索引本线程的一个key,也可用_thread.get_ident()得到,在线程退出后,标识符会被系统回收。在线程执行过程中可以调用_thread.exit()终止本线程的执行。 

    Java代码  收藏代码
    1. import _thread  
    2. import time  
    3. def threadFunction(count):  
    4.     for i in range(count):  
    5.       print('进程id为%d的打印%d'%(_thread.get_ident(),i))  
    6.       i-=1  
    7.       time.sleep(0.1)  
    8.   
    9. def begin():  
    10.   ident1=_thread.start_new_thread(threadFunction,(100,))  
    11.   print('启动标识符为%d的进程'%(ident1,))  
    12.   ident2=_thread.start_new_thread(threadFunction,(100,))  
    13.   print('启动标识符为%d的进程'%(ident2,))  
    14.   
    15.    
    16. if __name__ == '__main__':  
    17.   begin()  




    二.使用Thread类来实现多线程,这种方式是对_thread模块(如果没有_thread,则为dummy_threading)的高级封装,在这种方式下我们需创建新类继承threading.Thread,和java一样重写threading.Thread的run方法即可.启动线程用线程的start方法,它会调用我们重写的run方法. 

    Java代码  收藏代码
    1. class MyThread(threading.Thread):  
    2.     '''只能重写__init__ 和 run 两个方法'''  
    3.     def __init__(self,name):  
    4.         threading.Thread.__init__(self)  
    5.         self.name=name  
    6.         self.bool_stop=False  
    7.     def run(self):  
    8.         while not self.bool_stop:  
    9.             print('进程%s,于%s'%(self.name,time.asctime()))  
    10.             time.sleep(1)  
    11.     def stop(self):  
    12.         self.bool_stop = True  
    13.   
    14.   
    15. if __name__ == '__main__':  
    16.     th1=MyThread('one')  
    17.     th2=MyThread('two')  
    18.     th1.start()  
    19.     th2.start()  




    Thread类还定义了以下常用方法与属性: 

    Thread.getName() Thread.setName()
    老方式用于获取和设置线程的名称,官方建议用Thread.name替代
    Thread.ident
    获取线程的标识符。只有在调用start()方法执行后才有效,否则返回None。
    Thread.is_alive()
    判断线程是否是激活的。
    Thread.join([timeout])
    调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。



    Python中的锁 

    先用_thread模块的Lock锁来实现生产者消费者问题,Lock对象是Python提供的低级线程控制工具,使用起来非常简单,只需下面3条语句即可: 

    _thread.allocate_lock()返回一个新Lock对象,即为一个新锁
    lock.acquire() 相当于P操作,得到一个锁,
    lock.release()相当于V操作,释放一个锁


    代码如下: 

    Java代码  收藏代码
    1. import _thread,time,random  
    2. dish=0  
    3. lock = _thread.allocate_lock()  
    4. def producerFunction():  
    5.    '''如果投的筛子比0.2大,则向盘子中增加一个苹果'''  
    6.    global lock,dish  
    7.    while True:  
    8.        if(random.random() > 0.1):  
    9.          lock.acquire()  
    10.          if dish < 100:  
    11.            dish+=1  
    12.            print('生产者增加了一个苹果,现在有%d个苹果'%(dish,))  
    13.          lock.release()  
    14.          time.sleep(random.random()*3)  
    15.   
    16. def consumerFunction():  
    17.   '''如果投的筛子比0.5大,则从盘子中取一个苹果'''  
    18.   global lock,dish  
    19.   while True:  
    20.     if(random.random() > 0.9):  
    21.       lock.acquire()  
    22.       if dish > 0:  
    23.         dish-=1  
    24.         print('消费者拿走一个苹果现,在有%d个苹果'%(dish,))  
    25.       lock.release()  
    26.       time.sleep(random.random()*3)  
    27.   
    28. def begin():  
    29.   ident1=_thread.start_new_thread(producerFunction,())  
    30.   ident2=_thread.start_new_thread(consumerFunction,())   
    31. if __name__ == '__main__':  
    32.   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()
    将标识号设为Ture
    Event.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()
    唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。
  • 相关阅读:
    hdu 4027 Can you answer these queries? 线段树
    ZOJ1610 Count the Colors 线段树
    poj 2528 Mayor's posters 离散化 线段树
    hdu 1599 find the mincost route floyd求最小环
    POJ 2686 Traveling by Stagecoach 状压DP
    POJ 1990 MooFest 树状数组
    POJ 2955 Brackets 区间DP
    lightoj 1422 Halloween Costumes 区间DP
    模板 有源汇上下界最小流 loj117
    模板 有源汇上下界最大流 loj116
  • 原文地址:https://www.cnblogs.com/rrxc/p/3991079.html
Copyright © 2011-2022 走看看