Python线程学习

Author Avatar
Xin Qiu May 10, 2016
  • Read this article on other device

Python2.7中有两个常用的多线程库Multiprocessing,Threading。在Python中,线程和进程的区别在于线程模块使用线程,进程模块使用进程233,不开玩笑,这是StackOverFlow上的解释。说重点,线程使用相同的内存空间,而进程使用不同的。这也就让进程之间传对象稍有点困难。当然,由于线程共享内存空间,那么必须要考虑线程安全。

thread

thread算是轻量级的线程模块,它提供较为底层的多线程实现方案。使用start_new_thread(function, args[, kwargs])实现线程。使用allocate_lock()可以得到一个锁对象,用acquire()和release()来加锁和释放锁,用locked()来判断释放有锁。一把锁只能被一个线程得到,所以利用锁可以避免多个线程对同一资源的同时操作。

import thread
from time import sleep

def addLock(lock):
    lock.acquire() # 获得锁
    print lock.locked() # 判断是否有锁
    sleep(1)
    lock.release() # 释放锁

def main():
    lock = thread.allocate() # 分配一个锁对象
    thread.start_new(addLock,(lock,)) # 开辟一个线程
    thread.start_new(addLock,(lock,))
    sleep(3)

if __name__ == '__main__':
    main()

threading

threading作为一个更高级的模块,提供了一些thread没有的功能。threading中有两种锁,如threading.Lock(), threading.RLock()。

Lock

这里lock和thread模块里类似。

import threading

def addLock(lock):
    print lock.acquire(False)
    # lock.release()

def main():
    lock = threading.Lock()
    t1 = threading.Thread(target=addLock, args=(lock,))
    t2 = threading.Thread(target=addLock, args=(lock,))
    t1.run()
    t2.run()


if __name__ == '__main__':
    main()

以上代码演示了利用Threading模块来确定一把锁只能被获得一次。

RLock

RLock是可重入锁(reentrant lock),acquire()能够不被阻塞的被同一个线程调用多次。要注意的是release()需要调用与acquire()相同的次数才能释放锁。

import threading,time

rlock=threading.RLock()
result=[]

def step1():
    global result
    if rlock.acquire():
        result.append('step1')
        time.sleep(0)
        rlock.release()
def step2():
    global result
    if rlock.acquire():
        result.append('step2')
        time.sleep(0)
        rlock.release()

def showresult():
    print threading.current_thread() # 查看当前线程
    if rlock.acquire():
        step1()
        step2()
        rlock.release()
    print result

def clearresult():
    global result
    if rlock.acquire():
        result=None
        time.sleep(1)
        rlock.release()
    print threading.current_thread()
    print result

t1=threading.Thread(target=showresult)
t2=threading.Thread(target=clearresult)

t1.start()
t2.start()

Condition

条件同步机制是指:一个线程等待特定条件,而另一个线程发出特定条件满足的信号。 解释条件同步机制的一个很好的例子就是生产者/消费者(producer/consumer)模型。

Semaphore

信号量同步基于内部计数器,每调用一次acquire(),计数器减1;每调用一次release(),计数器加1.当计数器为0时,acquire()调用被阻塞。

Event

基于事件的同步是指:一个线程发送/传递事件,另外的线程等待事件的触发。在set()时, 其他线程就被唤醒执行。

# coding=utf-8

import threading, time
import random

class Producer(threading.Thread):
  """
  向列表中生产随机整数
  """

  def __init__(self, integers, event):
    """
    构造器

    @param integers 整数列表
    @param event 事件同步对象
    """
    threading.Thread.__init__(self)
    self.integers = integers
    self.event = event

  def run(self):
    """
    实现Thread的run方法。在随机时间向列表中添加一个随机整数
    """
    while True:
      integer = random.randint(0, 256)
      self.integers.append(integer)
      print '%d appended to list by %s' % (integer, self.name)
      print 'event set by %s' % self.name
      self.event.set()        #设置事件
      self.event.clear()    #发送事件
      print 'event cleared by %s' % self.name
      time.sleep(1)

class Consumer(threading.Thread):
  """
   从列表中消费整数
  """

  def __init__(self, integers, event):
    """
    构造器

    @param integers 整数列表
    @param event 事件同步对象
    """
    threading.Thread.__init__(self)
    self.integers = integers
    self.event = event

  def run(self):
    """
    实现Thread的run()方法,从列表中消费整数
    """
    while True:
      self.event.wait()    #等待事件被触发
      try:
        integer = self.integers.pop()
        print '%d popped from list by %s' % (integer, self.name)
      except IndexError:
        # catch pop on empty list
        time.sleep(1)

def main():
    integers = []
    event = threading.Event()
    t1 = Producer(integers, event)
    t2 = Consumer(integers, event)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

if __name__ == '__main__':
    main()