python--threading多线程总结

本文详细介绍了Python的threading模块,包括Thread、Lock、Rlock、Condition、Event、timer和local类的使用方法和实例,通过示例展示了它们在多线程中的作用,如线程同步、事件通信和定时任务。同时,强调了Lock和Rlock的区别,并提供了生产者消费者模型的应用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

  如果想了解更多Python的伙伴或者小白中有任何困难不懂的可以加入我的python交流学习QQ群:973998104,多多交流问题,互帮互助,群里有不错的学习教程和开发工具。资源分享

threading模块提供的类:

 
  1. Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading 模块提供的常用方法:

 
  1. threading.currentThread(): 返回当前的线程变量。

  2. threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

  3. threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

threading 模块提供的常量:

 
  1. threading.TIMEOUT_MAX 设置threading全局超时时间。

Thread类

Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run():

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4. #方法一:将要执行的方法作为参数传给Thread的构造方法

  5. def action(arg):

  6.    time.sleep(1)

  7.    print 'the arg is:%s\r' %arg

  8.  

  9. for i in xrange(4):

  10.    t =threading.Thread(target=action,args=(i,))

  11.    t.start()

  12.  

  13. print 'main thread end!'

  14.  

  15. #方法二:从Thread继承,并重写run()

  16. class MyThread(threading.Thread):

  17.    def __init__(self,arg):

  18.        super(MyThread, self).__init__()#注意:一定要显式的调用父类的初始化函数。

  19.        self.arg=arg

  20.    def run(self):#定义每个线程要运行的函数

  21.        time.sleep(1)

  22.        print 'the arg is:%s\r' % self.arg

  23.  

  24. for i in xrange(4):

  25.    t =MyThread(i)

  26.    t.start()

  27.  

  28. print 'main thread end!'

构造方法:

 
  1. Thread(group=None, target=None, name=None, args=(), kwargs={})

  2.  

  3.   group: 线程组,目前还没有实现,库引用中提示必须是None;

  4.   target: 要执行的方法;

  5.   name: 线程名;

  6.   args/kwargs: 要传入方法的参数。

实例方法:

 
  1. isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。

  2. get/setName(name): 获取/设置线程名。

  3. start():  线程准备就绪,等待CPU调度

  4. is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

  5.    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止

  6.    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

  7. start(): 启动线程。

  8. join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

使用例子一(未设置setDeamon):

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.start()

  14.  

  15. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. sub thread start!the thread name is:Thread-2

  3. the arg is:1

  4. the arg is:0

  5. sub thread start!the thread name is:Thread-4

  6. the arg is:2

  7. the arg is:3

  8. Process finished with exit code 0

可以看出,创建的4个“前台”线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止 复制代码 验证了serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。

使用例子二(setDeamon=True)

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.setDaemon(True)#设置线程为后台线程

  14.    t.start()

  15.  

  16. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. Process finished with exit code 0

  3. 可以看出,主线程执行完毕后,后台线程不管是成功与否,主线程均停止

验证了serDeamon(True)后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程均停止。

使用例子三(设置join)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11. thread_list = []    #线程存放列表

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    thread_list.append(t)

  16.  

  17. for t in thread_list:

  18.    t.start()

  19.  

  20. for t in thread_list:

  21.    t.join()

运行结果

 
  1. sub thread start!the thread name is:Thread-2    

  2. the arg is:1  

  3. sub thread start!the thread name is:Thread-3    

  4. the arg is:2  

  5. sub thread start!the thread name is:Thread-1    

  6. the arg is:0  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 设置join之后,主线程等待子线程全部执行完成后或者子线程超时后,主线程才结束

验证了 join()阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)主线程依然要等待子线程结束。

使用例子四(join不妥当的用法,使多线程编程顺序执行)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11.  

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    t.start()

  16.    t.join()

  17.  

  18. print 'main_thread end!'

运行结果

 
  1. sub thread start!the thread name is:Thread-1    

  2. the arg is:0  

  3. sub thread start!the thread name is:Thread-2    

  4. the arg is:1  

  5. sub thread start!the thread name is:Thread-3    

  6. the arg is:2  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 可以看出此时,程序只能顺序执行,每个线程都被上一个线程的join阻塞,使得“多线程”失去了多线程意义。

Lock、Rlock类

  由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁。

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

简言之:Lock属于全局,Rlock属于线程。

构造方法: Lock(),Rlock(),推荐使用Rlock()

实例方法:

 
  1.   acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。

  2.   release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

例子一(未使用锁):

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. gl_num = 0

  6.  

  7. def show(arg):

  8.    global gl_num

  9.    time.sleep(1)

  10.    gl_num +=1

  11.    print gl_num

  12.  

  13. for i in range(10):

  14.    t = threading.Thread(target=show, args=(i,))

  15.    t.start()

  16.  

  17. print 'main thread stop'

运行结果

 
  1. main thread stop

  2. 12

  3.  

  4. 3

  5. 4

  6. 568

  7. 9

  8.  

  9. 910

  10.  

  11.  

  12. Process finished with exit code 0

  13.  

  14. 多次运行可能产生混乱。这种场景就是适合使用锁的场景。

例子二(使用锁):

 
  1. # coding:utf-8

  2.  

  3. import threading

  4. import time

  5.  

  6. gl_num = 0

  7.  

  8. lock = threading.RLock()

  9.  

  10.  

  11. # 调用acquire([timeout])时,线程将一直阻塞,

  12. # 直到获得锁定或者直到timeout秒后(timeout参数可选)。

  13. # 返回是否获得锁。

  14. def Func():

  15.    lock.acquire()

  16.    global gl_num

  17.    gl_num += 1

  18.    time.sleep(1)

  19.    print gl_num

  20.    lock.release()

  21.  

  22.  

  23. for i in range(10):

  24.    t = threading.Thread(target=Func)

  25.    t.start()

运行结果

 
  1. 1

  2. 2

  3. 3

  4. 4

  5. 5

  6. 6

  7. 7

  8. 8

  9. 9

  10. 10

  11.  

  12. Process finished with exit code 0

  13. 可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性

Lock对比Rlock

 
  1. #coding:utf-8

  2.  

  3. import threading

  4. lock = threading.Lock() #Lock对象

  5. lock.acquire()

  6. lock.acquire()  #产生了死锁。

  7. lock.release()

  8. lock.release()

  9. print lock.acquire()

  10.  

  11.  

  12. import threading

  13. rLock = threading.RLock()  #RLock对象

  14. rLock.acquire()

  15. rLock.acquire() #在同一线程内,程序不会堵塞。

  16. rLock.release()

  17. rLock.release()

Condition类

  Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

  可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

构造方法: Condition([lock/rlock])

实例方法:

 
  1. acquire([timeout])/release(): 调用关联的锁的相应方法。

  2. wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。

  3. notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

  4. notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

例子一:生产者消费者模型

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. # 商品

  6. product = None

  7. # 条件变量

  8. con = threading.Condition()

  9.  

  10.  

  11. # 生产者方法

  12. def produce():

  13.    global product

  14.  

  15.    if con.acquire():

  16.        while True:

  17.            if product is None:

  18.                print 'produce...'

  19.                product = 'anything'

  20.  

  21.                # 通知消费者,商品已经生产

  22.                con.notify()

  23.  

  24.            # 等待通知

  25.            con.wait()

  26.            time.sleep(2)

  27.  

  28.  

  29. # 消费者方法

  30. def consume():

  31.    global product

  32.  

  33.    if con.acquire():

  34.        while True:

  35.            if product is not None:

  36.                print 'consume...'

  37.                product = None

  38.  

  39.                # 通知生产者,商品已经没了

  40.                con.notify()

  41.  

  42.            # 等待通知

  43.            con.wait()

  44.            time.sleep(2)

  45.  

  46.  

  47. t1 = threading.Thread(target=produce)

  48. t2 = threading.Thread(target=consume)

  49. t2.start()

  50. t1.start()

运行结果

 
  1. produce...

  2. consume...

  3. produce...

  4. consume...

  5. produce...

  6. consume...

  7. produce...

  8. consume...

  9. produce...

  10. consume...

  11.  

  12. Process finished with exit code -1

  13. 程序不断循环运行下去。重复生产消费过程。

例子二:生产者消费者模型

 
  1. import threading

  2. import time

  3.  

  4. condition = threading.Condition()

  5. products = 0

  6.  

  7. class Producer(threading.Thread):

  8.    def run(self):

  9.        global products

  10.        while True:

  11.            if condition.acquire():

  12.                if products < 10:

  13.                    products += 1;

  14.                    print "Producer(%s):deliver one, now products:%s" %(self.name, products)

  15.                    condition.notify()#不释放锁定,因此需要下面一句

  16.                    condition.release()

  17.                else:

  18.                    print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)

  19.                    condition.wait();#自动释放锁定

  20.                time.sleep(2)

  21.  

  22. class Consumer(threading.Thread):

  23.    def run(self):

  24.        global products

  25.        while True:

  26.            if condition.acquire():

  27.                if products > 1:

  28.                    products -= 1

  29.                    print "Consumer(%s):consume one, now products:%s" %(self.name, products)

  30.                    condition.notify()

  31.                    condition.release()

  32.                else:

  33.                    print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)

  34.                    condition.wait();

  35.                time.sleep(2)

  36.  

  37. if __name__ == "__main__":

  38.    for p in range(0, 2):

  39.        p = Producer()

  40.        p.start()

  41.  

  42.    for c in range(0, 3):

  43.        c = Consumer()

  44.        c.start()

例子三:

 
  1. import threading

  2.  

  3. alist = None

  4. condition = threading.Condition()

  5.  

  6. def doSet():

  7.    if condition.acquire():

  8.        while alist is None:

  9.            condition.wait()

  10.        for i in range(len(alist))[::-1]:

  11.            alist[i] = 1

  12.        condition.release()

  13.  

  14. def doPrint():

  15.    if condition.acquire():

  16.        while alist is None:

  17.            condition.wait()

  18.        for i in alist:

  19.            print i,

  20.        print

  21.        condition.release()

  22.  

  23. def doCreate():

  24.    global alist

  25.    if condition.acquire():

  26.        if alist is None:

  27.            alist = [0 for i in range(10)]

  28.            condition.notifyAll()

  29.        condition.release()

  30.  

  31. tset = threading.Thread(target=doSet,name='tset')

  32. tprint = threading.Thread(target=doPrint,name='tprint')

  33. tcreate = threading.Thread(target=doCreate,name='tcreate')

  34. tset.start()

  35. tprint.start()

  36. tcreate.start()

Event类

  Event(事件)是最简单的线程通信机制之一:一个线程通知事件,其他线程等待事件。Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。

  Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。

构造方法: Event()

实例方法:

 
  1. isSet(): 当内置标志为True时返回True。

  2. set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态。

  3. clear(): 将标志设为False。

  4. wait([timeout]): 如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。

例子一

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. event = threading.Event()

  6.  

  7.  

  8. def func():

  9.    # 等待事件,进入等待阻塞状态

  10.    print '%s wait for event...' % threading.currentThread().getName()

  11.    event.wait()

  12.  

  13.    # 收到事件后进入运行状态

  14.    print '%s recv event.' % threading.currentThread().getName()

  15.  

  16.  

  17. t1 = threading.Thread(target=func)

  18. t2 = threading.Thread(target=func)

  19. t1.start()

  20. t2.start()

  21.  

  22. time.sleep(2)

  23.  

  24. # 发送事件通知

  25. print 'MainThread set event.'

  26. event.set()

运行结果

 
  1. Thread-1 wait for event...

  2. Thread-2 wait for event...

  3.  

  4. #2秒后。。。

  5. MainThread set event.

  6. Thread-1 recv event.

  7. Thread-2 recv event.

  8.  

  9. Process finished with exit code 0

timer类

  Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。

构造方法:

 
  1. Timer(interval, function, args=[], kwargs={})

  2.   interval: 指定的时间

  3.   function: 要执行的方法

  4.   args/kwargs: 方法的参数

实例方法: Timer从Thread派生,没有增加实例方法。

例子一:

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4.  

  5. def func():

  6.    print 'hello timer!'

  7.  

  8.  

  9. timer = threading.Timer(5, func)

  10. timer.start()

线程延迟5秒后执行。

local类

  local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程无法访问其他线程设置的属性;线程设置的属性不会被其他线程设置的同名属性替换。

  可以把local看成是一个“线程-属性字典”的字典,local封装了从自身使用线程作为 key检索对应的属性字典、再使用属性名作为key检索属性值的细节。

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4. local = threading.local()

  5. local.tname = 'main'

  6.  

  7. def func():

  8.    local.tname = 'notmain'

  9.    print local.tname

  10.  

  11. t1 = threading.Thread(target=func)

  12. t1.start()

  13. t1.join()

  14.  

  15. print local.tname

运行结果

 
  1. notmain

  2. main

 

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

threading模块提供的类:

 
  1. Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading 模块提供的常用方法:

 
  1. threading.currentThread(): 返回当前的线程变量。

  2. threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

  3. threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

threading 模块提供的常量:

 
  1. threading.TIMEOUT_MAX 设置threading全局超时时间。

Thread类

Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run():

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4. #方法一:将要执行的方法作为参数传给Thread的构造方法

  5. def action(arg):

  6.    time.sleep(1)

  7.    print 'the arg is:%s\r' %arg

  8.  

  9. for i in xrange(4):

  10.    t =threading.Thread(target=action,args=(i,))

  11.    t.start()

  12.  

  13. print 'main thread end!'

  14.  

  15. #方法二:从Thread继承,并重写run()

  16. class MyThread(threading.Thread):

  17.    def __init__(self,arg):

  18.        super(MyThread, self).__init__()#注意:一定要显式的调用父类的初始化函数。

  19.        self.arg=arg

  20.    def run(self):#定义每个线程要运行的函数

  21.        time.sleep(1)

  22.        print 'the arg is:%s\r' % self.arg

  23.  

  24. for i in xrange(4):

  25.    t =MyThread(i)

  26.    t.start()

  27.  

  28. print 'main thread end!'

构造方法:

 
  1. Thread(group=None, target=None, name=None, args=(), kwargs={})

  2.  

  3.   group: 线程组,目前还没有实现,库引用中提示必须是None;

  4.   target: 要执行的方法;

  5.   name: 线程名;

  6.   args/kwargs: 要传入方法的参数。

实例方法:

 
  1. isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。

  2. get/setName(name): 获取/设置线程名。

  3. start():  线程准备就绪,等待CPU调度

  4. is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

  5.    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止

  6.    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

  7. start(): 启动线程。

  8. join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

使用例子一(未设置setDeamon):

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.start()

  14.  

  15. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. sub thread start!the thread name is:Thread-2

  3. the arg is:1

  4. the arg is:0

  5. sub thread start!the thread name is:Thread-4

  6. the arg is:2

  7. the arg is:3

  8. Process finished with exit code 0

可以看出,创建的4个“前台”线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止 复制代码 验证了serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。

使用例子二(setDeamon=True)

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.setDaemon(True)#设置线程为后台线程

  14.    t.start()

  15.  

  16. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. Process finished with exit code 0

  3. 可以看出,主线程执行完毕后,后台线程不管是成功与否,主线程均停止

验证了serDeamon(True)后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程均停止。

使用例子三(设置join)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11. thread_list = []    #线程存放列表

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    thread_list.append(t)

  16.  

  17. for t in thread_list:

  18.    t.start()

  19.  

  20. for t in thread_list:

  21.    t.join()

运行结果

 
  1. sub thread start!the thread name is:Thread-2    

  2. the arg is:1  

  3. sub thread start!the thread name is:Thread-3    

  4. the arg is:2  

  5. sub thread start!the thread name is:Thread-1    

  6. the arg is:0  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 设置join之后,主线程等待子线程全部执行完成后或者子线程超时后,主线程才结束

验证了 join()阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)主线程依然要等待子线程结束。

使用例子四(join不妥当的用法,使多线程编程顺序执行)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11.  

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    t.start()

  16.    t.join()

  17.  

  18. print 'main_thread end!'

运行结果

 
  1. sub thread start!the thread name is:Thread-1    

  2. the arg is:0  

  3. sub thread start!the thread name is:Thread-2    

  4. the arg is:1  

  5. sub thread start!the thread name is:Thread-3    

  6. the arg is:2  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 可以看出此时,程序只能顺序执行,每个线程都被上一个线程的join阻塞,使得“多线程”失去了多线程意义。

Lock、Rlock类

  由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁。

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

简言之:Lock属于全局,Rlock属于线程。

构造方法: Lock(),Rlock(),推荐使用Rlock()

实例方法:

 
  1.   acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。

  2.   release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

例子一(未使用锁):

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. gl_num = 0

  6.  

  7. def show(arg):

  8.    global gl_num

  9.    time.sleep(1)

  10.    gl_num +=1

  11.    print gl_num

  12.  

  13. for i in range(10):

  14.    t = threading.Thread(target=show, args=(i,))

  15.    t.start()

  16.  

  17. print 'main thread stop'

运行结果

 
  1. main thread stop

  2. 12

  3.  

  4. 3

  5. 4

  6. 568

  7. 9

  8.  

  9. 910

  10.  

  11.  

  12. Process finished with exit code 0

  13.  

  14. 多次运行可能产生混乱。这种场景就是适合使用锁的场景。

例子二(使用锁):

 
  1. # coding:utf-8

  2.  

  3. import threading

  4. import time

  5.  

  6. gl_num = 0

  7.  

  8. lock = threading.RLock()

  9.  

  10.  

  11. # 调用acquire([timeout])时,线程将一直阻塞,

  12. # 直到获得锁定或者直到timeout秒后(timeout参数可选)。

  13. # 返回是否获得锁。

  14. def Func():

  15.    lock.acquire()

  16.    global gl_num

  17.    gl_num += 1

  18.    time.sleep(1)

  19.    print gl_num

  20.    lock.release()

  21.  

  22.  

  23. for i in range(10):

  24.    t = threading.Thread(target=Func)

  25.    t.start()

运行结果

 
  1. 1

  2. 2

  3. 3

  4. 4

  5. 5

  6. 6

  7. 7

  8. 8

  9. 9

  10. 10

  11.  

  12. Process finished with exit code 0

  13. 可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性

Lock对比Rlock

 
  1. #coding:utf-8

  2.  

  3. import threading

  4. lock = threading.Lock() #Lock对象

  5. lock.acquire()

  6. lock.acquire()  #产生了死锁。

  7. lock.release()

  8. lock.release()

  9. print lock.acquire()

  10.  

  11.  

  12. import threading

  13. rLock = threading.RLock()  #RLock对象

  14. rLock.acquire()

  15. rLock.acquire() #在同一线程内,程序不会堵塞。

  16. rLock.release()

  17. rLock.release()

Condition类

  Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

  可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

构造方法: Condition([lock/rlock])

实例方法:

 
  1. acquire([timeout])/release(): 调用关联的锁的相应方法。

  2. wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。

  3. notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

  4. notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

例子一:生产者消费者模型

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. # 商品

  6. product = None

  7. # 条件变量

  8. con = threading.Condition()

  9.  

  10.  

  11. # 生产者方法

  12. def produce():

  13.    global product

  14.  

  15.    if con.acquire():

  16.        while True:

  17.            if product is None:

  18.                print 'produce...'

  19.                product = 'anything'

  20.  

  21.                # 通知消费者,商品已经生产

  22.                con.notify()

  23.  

  24.            # 等待通知

  25.            con.wait()

  26.            time.sleep(2)

  27.  

  28.  

  29. # 消费者方法

  30. def consume():

  31.    global product

  32.  

  33.    if con.acquire():

  34.        while True:

  35.            if product is not None:

  36.                print 'consume...'

  37.                product = None

  38.  

  39.                # 通知生产者,商品已经没了

  40.                con.notify()

  41.  

  42.            # 等待通知

  43.            con.wait()

  44.            time.sleep(2)

  45.  

  46.  

  47. t1 = threading.Thread(target=produce)

  48. t2 = threading.Thread(target=consume)

  49. t2.start()

  50. t1.start()

运行结果

 
  1. produce...

  2. consume...

  3. produce...

  4. consume...

  5. produce...

  6. consume...

  7. produce...

  8. consume...

  9. produce...

  10. consume...

  11.  

  12. Process finished with exit code -1

  13. 程序不断循环运行下去。重复生产消费过程。

例子二:生产者消费者模型

 
  1. import threading

  2. import time

  3.  

  4. condition = threading.Condition()

  5. products = 0

  6.  

  7. class Producer(threading.Thread):

  8.    def run(self):

  9.        global products

  10.        while True:

  11.            if condition.acquire():

  12.                if products < 10:

  13.                    products += 1;

  14.                    print "Producer(%s):deliver one, now products:%s" %(self.name, products)

  15.                    condition.notify()#不释放锁定,因此需要下面一句

  16.                    condition.release()

  17.                else:

  18.                    print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)

  19.                    condition.wait();#自动释放锁定

  20.                time.sleep(2)

  21.  

  22. class Consumer(threading.Thread):

  23.    def run(self):

  24.        global products

  25.        while True:

  26.            if condition.acquire():

  27.                if products > 1:

  28.                    products -= 1

  29.                    print "Consumer(%s):consume one, now products:%s" %(self.name, products)

  30.                    condition.notify()

  31.                    condition.release()

  32.                else:

  33.                    print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)

  34.                    condition.wait();

  35.                time.sleep(2)

  36.  

  37. if __name__ == "__main__":

  38.    for p in range(0, 2):

  39.        p = Producer()

  40.        p.start()

  41.  

  42.    for c in range(0, 3):

  43.        c = Consumer()

  44.        c.start()

例子三:

 
  1. import threading

  2.  

  3. alist = None

  4. condition = threading.Condition()

  5.  

  6. def doSet():

  7.    if condition.acquire():

  8.        while alist is None:

  9.            condition.wait()

  10.        for i in range(len(alist))[::-1]:

  11.            alist[i] = 1

  12.        condition.release()

  13.  

  14. def doPrint():

  15.    if condition.acquire():

  16.        while alist is None:

  17.            condition.wait()

  18.        for i in alist:

  19.            print i,

  20.        print

  21.        condition.release()

  22.  

  23. def doCreate():

  24.    global alist

  25.    if condition.acquire():

  26.        if alist is None:

  27.            alist = [0 for i in range(10)]

  28.            condition.notifyAll()

  29.        condition.release()

  30.  

  31. tset = threading.Thread(target=doSet,name='tset')

  32. tprint = threading.Thread(target=doPrint,name='tprint')

  33. tcreate = threading.Thread(target=doCreate,name='tcreate')

  34. tset.start()

  35. tprint.start()

  36. tcreate.start()

Event类

  Event(事件)是最简单的线程通信机制之一:一个线程通知事件,其他线程等待事件。Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。

  Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。

构造方法: Event()

实例方法:

 
  1. isSet(): 当内置标志为True时返回True。

  2. set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态。

  3. clear(): 将标志设为False。

  4. wait([timeout]): 如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。

例子一

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. event = threading.Event()

  6.  

  7.  

  8. def func():

  9.    # 等待事件,进入等待阻塞状态

  10.    print '%s wait for event...' % threading.currentThread().getName()

  11.    event.wait()

  12.  

  13.    # 收到事件后进入运行状态

  14.    print '%s recv event.' % threading.currentThread().getName()

  15.  

  16.  

  17. t1 = threading.Thread(target=func)

  18. t2 = threading.Thread(target=func)

  19. t1.start()

  20. t2.start()

  21.  

  22. time.sleep(2)

  23.  

  24. # 发送事件通知

  25. print 'MainThread set event.'

  26. event.set()

运行结果

 
  1. Thread-1 wait for event...

  2. Thread-2 wait for event...

  3.  

  4. #2秒后。。。

  5. MainThread set event.

  6. Thread-1 recv event.

  7. Thread-2 recv event.

  8.  

  9. Process finished with exit code 0

timer类

  Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。

构造方法:

 
  1. Timer(interval, function, args=[], kwargs={})

  2.   interval: 指定的时间

  3.   function: 要执行的方法

  4.   args/kwargs: 方法的参数

实例方法: Timer从Thread派生,没有增加实例方法。

例子一:

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4.  

  5. def func():

  6.    print 'hello timer!'

  7.  

  8.  

  9. timer = threading.Timer(5, func)

  10. timer.start()

线程延迟5秒后执行。

local类

  local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程无法访问其他线程设置的属性;线程设置的属性不会被其他线程设置的同名属性替换。

  可以把local看成是一个“线程-属性字典”的字典,local封装了从自身使用线程作为 key检索对应的属性字典、再使用属性名作为key检索属性值的细节。

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4. local = threading.local()

  5. local.tname = 'main'

  6.  

  7. def func():

  8.    local.tname = 'notmain'

  9.    print local.tname

  10.  

  11. t1 = threading.Thread(target=func)

  12. t1.start()

  13. t1.join()

  14.  

  15. print local.tname

运行结果

 
  1. notmain

  2. main

 

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

threading模块提供的类:

 
  1. Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading 模块提供的常用方法:

 
  1. threading.currentThread(): 返回当前的线程变量。

  2. threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

  3. threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

threading 模块提供的常量:

 
  1. threading.TIMEOUT_MAX 设置threading全局超时时间。

Thread类

Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run():

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4. #方法一:将要执行的方法作为参数传给Thread的构造方法

  5. def action(arg):

  6.    time.sleep(1)

  7.    print 'the arg is:%s\r' %arg

  8.  

  9. for i in xrange(4):

  10.    t =threading.Thread(target=action,args=(i,))

  11.    t.start()

  12.  

  13. print 'main thread end!'

  14.  

  15. #方法二:从Thread继承,并重写run()

  16. class MyThread(threading.Thread):

  17.    def __init__(self,arg):

  18.        super(MyThread, self).__init__()#注意:一定要显式的调用父类的初始化函数。

  19.        self.arg=arg

  20.    def run(self):#定义每个线程要运行的函数

  21.        time.sleep(1)

  22.        print 'the arg is:%s\r' % self.arg

  23.  

  24. for i in xrange(4):

  25.    t =MyThread(i)

  26.    t.start()

  27.  

  28. print 'main thread end!'

构造方法:

 
  1. Thread(group=None, target=None, name=None, args=(), kwargs={})

  2.  

  3.   group: 线程组,目前还没有实现,库引用中提示必须是None;

  4.   target: 要执行的方法;

  5.   name: 线程名;

  6.   args/kwargs: 要传入方法的参数。

实例方法:

 
  1. isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。

  2. get/setName(name): 获取/设置线程名。

  3. start():  线程准备就绪,等待CPU调度

  4. is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

  5.    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止

  6.    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

  7. start(): 启动线程。

  8. join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

使用例子一(未设置setDeamon):

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.start()

  14.  

  15. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. sub thread start!the thread name is:Thread-2

  3. the arg is:1

  4. the arg is:0

  5. sub thread start!the thread name is:Thread-4

  6. the arg is:2

  7. the arg is:3

  8. Process finished with exit code 0

可以看出,创建的4个“前台”线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止 复制代码 验证了serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。

使用例子二(setDeamon=True)

 
  1. # coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()

  8.    print 'the arg is:%s\r' %arg

  9.    time.sleep(1)

  10.  

  11. for i in xrange(4):

  12.    t =threading.Thread(target=action,args=(i,))

  13.    t.setDaemon(True)#设置线程为后台线程

  14.    t.start()

  15.  

  16. print 'main_thread end!'

运行结果

 
  1. main_thread end!

  2. Process finished with exit code 0

  3. 可以看出,主线程执行完毕后,后台线程不管是成功与否,主线程均停止

验证了serDeamon(True)后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程均停止。

使用例子三(设置join)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11. thread_list = []    #线程存放列表

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    thread_list.append(t)

  16.  

  17. for t in thread_list:

  18.    t.start()

  19.  

  20. for t in thread_list:

  21.    t.join()

运行结果

 
  1. sub thread start!the thread name is:Thread-2    

  2. the arg is:1  

  3. sub thread start!the thread name is:Thread-3    

  4. the arg is:2  

  5. sub thread start!the thread name is:Thread-1    

  6. the arg is:0  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 设置join之后,主线程等待子线程全部执行完成后或者子线程超时后,主线程才结束

验证了 join()阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)主线程依然要等待子线程结束。

使用例子四(join不妥当的用法,使多线程编程顺序执行)

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. def action(arg):

  6.    time.sleep(1)

  7.    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()

  8.    print 'the arg is:%s   ' %arg

  9.    time.sleep(1)

  10.  

  11.  

  12. for i in xrange(4):

  13.    t =threading.Thread(target=action,args=(i,))

  14.    t.setDaemon(True)

  15.    t.start()

  16.    t.join()

  17.  

  18. print 'main_thread end!'

运行结果

 
  1. sub thread start!the thread name is:Thread-1    

  2. the arg is:0  

  3. sub thread start!the thread name is:Thread-2    

  4. the arg is:1  

  5. sub thread start!the thread name is:Thread-3    

  6. the arg is:2  

  7. sub thread start!the thread name is:Thread-4    

  8. the arg is:3  

  9. main_thread end!

  10.  

  11. Process finished with exit code 0

  12. 可以看出此时,程序只能顺序执行,每个线程都被上一个线程的join阻塞,使得“多线程”失去了多线程意义。

Lock、Rlock类

  由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁。

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

简言之:Lock属于全局,Rlock属于线程。

构造方法: Lock(),Rlock(),推荐使用Rlock()

实例方法:

 
  1.   acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。

  2.   release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

例子一(未使用锁):

 
  1. #coding:utf-8

  2. import threading

  3. import time

  4.  

  5. gl_num = 0

  6.  

  7. def show(arg):

  8.    global gl_num

  9.    time.sleep(1)

  10.    gl_num +=1

  11.    print gl_num

  12.  

  13. for i in range(10):

  14.    t = threading.Thread(target=show, args=(i,))

  15.    t.start()

  16.  

  17. print 'main thread stop'

运行结果

 
  1. main thread stop

  2. 12

  3.  

  4. 3

  5. 4

  6. 568

  7. 9

  8.  

  9. 910

  10.  

  11.  

  12. Process finished with exit code 0

  13.  

  14. 多次运行可能产生混乱。这种场景就是适合使用锁的场景。

例子二(使用锁):

 
  1. # coding:utf-8

  2.  

  3. import threading

  4. import time

  5.  

  6. gl_num = 0

  7.  

  8. lock = threading.RLock()

  9.  

  10.  

  11. # 调用acquire([timeout])时,线程将一直阻塞,

  12. # 直到获得锁定或者直到timeout秒后(timeout参数可选)。

  13. # 返回是否获得锁。

  14. def Func():

  15.    lock.acquire()

  16.    global gl_num

  17.    gl_num += 1

  18.    time.sleep(1)

  19.    print gl_num

  20.    lock.release()

  21.  

  22.  

  23. for i in range(10):

  24.    t = threading.Thread(target=Func)

  25.    t.start()

运行结果

 
  1. 1

  2. 2

  3. 3

  4. 4

  5. 5

  6. 6

  7. 7

  8. 8

  9. 9

  10. 10

  11.  

  12. Process finished with exit code 0

  13. 可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性

Lock对比Rlock

 
  1. #coding:utf-8

  2.  

  3. import threading

  4. lock = threading.Lock() #Lock对象

  5. lock.acquire()

  6. lock.acquire()  #产生了死锁。

  7. lock.release()

  8. lock.release()

  9. print lock.acquire()

  10.  

  11.  

  12. import threading

  13. rLock = threading.RLock()  #RLock对象

  14. rLock.acquire()

  15. rLock.acquire() #在同一线程内,程序不会堵塞。

  16. rLock.release()

  17. rLock.release()

Condition类

  Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

  可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

构造方法: Condition([lock/rlock])

实例方法:

 
  1. acquire([timeout])/release(): 调用关联的锁的相应方法。

  2. wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。

  3. notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

  4. notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

例子一:生产者消费者模型

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. # 商品

  6. product = None

  7. # 条件变量

  8. con = threading.Condition()

  9.  

  10.  

  11. # 生产者方法

  12. def produce():

  13.    global product

  14.  

  15.    if con.acquire():

  16.        while True:

  17.            if product is None:

  18.                print 'produce...'

  19.                product = 'anything'

  20.  

  21.                # 通知消费者,商品已经生产

  22.                con.notify()

  23.  

  24.            # 等待通知

  25.            con.wait()

  26.            time.sleep(2)

  27.  

  28.  

  29. # 消费者方法

  30. def consume():

  31.    global product

  32.  

  33.    if con.acquire():

  34.        while True:

  35.            if product is not None:

  36.                print 'consume...'

  37.                product = None

  38.  

  39.                # 通知生产者,商品已经没了

  40.                con.notify()

  41.  

  42.            # 等待通知

  43.            con.wait()

  44.            time.sleep(2)

  45.  

  46.  

  47. t1 = threading.Thread(target=produce)

  48. t2 = threading.Thread(target=consume)

  49. t2.start()

  50. t1.start()

运行结果

 
  1. produce...

  2. consume...

  3. produce...

  4. consume...

  5. produce...

  6. consume...

  7. produce...

  8. consume...

  9. produce...

  10. consume...

  11.  

  12. Process finished with exit code -1

  13. 程序不断循环运行下去。重复生产消费过程。

例子二:生产者消费者模型

 
  1. import threading

  2. import time

  3.  

  4. condition = threading.Condition()

  5. products = 0

  6.  

  7. class Producer(threading.Thread):

  8.    def run(self):

  9.        global products

  10.        while True:

  11.            if condition.acquire():

  12.                if products < 10:

  13.                    products += 1;

  14.                    print "Producer(%s):deliver one, now products:%s" %(self.name, products)

  15.                    condition.notify()#不释放锁定,因此需要下面一句

  16.                    condition.release()

  17.                else:

  18.                    print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)

  19.                    condition.wait();#自动释放锁定

  20.                time.sleep(2)

  21.  

  22. class Consumer(threading.Thread):

  23.    def run(self):

  24.        global products

  25.        while True:

  26.            if condition.acquire():

  27.                if products > 1:

  28.                    products -= 1

  29.                    print "Consumer(%s):consume one, now products:%s" %(self.name, products)

  30.                    condition.notify()

  31.                    condition.release()

  32.                else:

  33.                    print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)

  34.                    condition.wait();

  35.                time.sleep(2)

  36.  

  37. if __name__ == "__main__":

  38.    for p in range(0, 2):

  39.        p = Producer()

  40.        p.start()

  41.  

  42.    for c in range(0, 3):

  43.        c = Consumer()

  44.        c.start()

例子三:

 
  1. import threading

  2.  

  3. alist = None

  4. condition = threading.Condition()

  5.  

  6. def doSet():

  7.    if condition.acquire():

  8.        while alist is None:

  9.            condition.wait()

  10.        for i in range(len(alist))[::-1]:

  11.            alist[i] = 1

  12.        condition.release()

  13.  

  14. def doPrint():

  15.    if condition.acquire():

  16.        while alist is None:

  17.            condition.wait()

  18.        for i in alist:

  19.            print i,

  20.        print

  21.        condition.release()

  22.  

  23. def doCreate():

  24.    global alist

  25.    if condition.acquire():

  26.        if alist is None:

  27.            alist = [0 for i in range(10)]

  28.            condition.notifyAll()

  29.        condition.release()

  30.  

  31. tset = threading.Thread(target=doSet,name='tset')

  32. tprint = threading.Thread(target=doPrint,name='tprint')

  33. tcreate = threading.Thread(target=doCreate,name='tcreate')

  34. tset.start()

  35. tprint.start()

  36. tcreate.start()

Event类

  Event(事件)是最简单的线程通信机制之一:一个线程通知事件,其他线程等待事件。Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。

  Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。

构造方法: Event()

实例方法:

 
  1. isSet(): 当内置标志为True时返回True。

  2. set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态。

  3. clear(): 将标志设为False。

  4. wait([timeout]): 如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。

例子一

 
  1. # encoding: UTF-8

  2. import threading

  3. import time

  4.  

  5. event = threading.Event()

  6.  

  7.  

  8. def func():

  9.    # 等待事件,进入等待阻塞状态

  10.    print '%s wait for event...' % threading.currentThread().getName()

  11.    event.wait()

  12.  

  13.    # 收到事件后进入运行状态

  14.    print '%s recv event.' % threading.currentThread().getName()

  15.  

  16.  

  17. t1 = threading.Thread(target=func)

  18. t2 = threading.Thread(target=func)

  19. t1.start()

  20. t2.start()

  21.  

  22. time.sleep(2)

  23.  

  24. # 发送事件通知

  25. print 'MainThread set event.'

  26. event.set()

运行结果

 
  1. Thread-1 wait for event...

  2. Thread-2 wait for event...

  3.  

  4. #2秒后。。。

  5. MainThread set event.

  6. Thread-1 recv event.

  7. Thread-2 recv event.

  8.  

  9. Process finished with exit code 0

timer类

  Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。

构造方法:

 
  1. Timer(interval, function, args=[], kwargs={})

  2.   interval: 指定的时间

  3.   function: 要执行的方法

  4.   args/kwargs: 方法的参数

实例方法: Timer从Thread派生,没有增加实例方法。

例子一:

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4.  

  5. def func():

  6.    print 'hello timer!'

  7.  

  8.  

  9. timer = threading.Timer(5, func)

  10. timer.start()

线程延迟5秒后执行。

local类

  local是一个小写字母开头的类,用于管理 thread-local(线程局部的)数据。对于同一个local,线程无法访问其他线程设置的属性;线程设置的属性不会被其他线程设置的同名属性替换。

  可以把local看成是一个“线程-属性字典”的字典,local封装了从自身使用线程作为 key检索对应的属性字典、再使用属性名作为key检索属性值的细节。

 
  1. # encoding: UTF-8

  2. import threading

  3.  

  4. local = threading.local()

  5. local.tname = 'main'

  6.  

  7. def func():

  8.    local.tname = 'notmain'

  9.    print local.tname

  10.  

  11. t1 = threading.Thread(target=func)

  12. t1.start()

  13. t1.join()

  14.  

  15. print local.tname

运行结果

 
  1. notmain

  2. main

 

  如果想了解更多Python的伙伴或者小白中有任何困难不懂的可以加入我的python交流学习QQ群:973998104,多多交流问题,互帮互助,群里有不错的学习教程和开发工具。资源分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值