python 多线程受制于Global Interpreter Lock(GIL)并不能充分利用多处理器,仅仅是多线程同步使用一个处理器,因此该模块适用于I/O为主的程序。

1. Thread对象
  class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
  使用上面函数创建一个新的Thread实例。
  target:即线程的目标函数,线程启动时,run()方法将调用此函数。
  name:线程的名字,是一个字符串;默认将创建一个“Thread-N”格式的唯一名称。
  args:传递给target函数的参数元组;注意,必须是元组,因此注意仅有一个参数时的情况。
  Thread实例t支持以下方法和属性:
  (1) t.start()
    通过在一个单独的控制线程中调用run()方法,启动线程。此方法只能调用一次。
  (2) t.run()
    线程启动时将调用此方法。默认情况,它将调用传递到构造函数中的target函数;除此之外,还可以在Thread子类中重新定义此方法。
  (3) t.is_alive()
    如果线程是活动的,返回True;否则返回False。
  (4) t.name
    线程名称,是一个属性。可以通过它更改或获得线程的名字。
  (5) t.daemon
    线程的布尔型后台标志,是一个属性。必须在调用t.start()之前设置该值。它表示该线程是否是以daemon的形式执行,它的初始值继承自创建它的线程,因此一般是False。
    threading会在主线程执行完毕后,检查是否有daemon为False的子线程,如果有,主线程就wait,等待子线程结束,在等待期间,所有发送到主线程的信号也会被阻塞,因此Ctrl-C不起作用。如果子线程的daemon都是True,那么主线程执行完毕后不会等待,整个程序(包括主线程和子线程)立即结束。
    因此,比较常用的方法,就是将子线程的daemon设为True,并且在主线程结束前轮寻检测。
  (6) t.join([timeout])
    等待线程t,直到t终止或出现超时为止。timeout是一个浮点数,用于指定以秒为单位的超时时间。线程不能够join自己,而且不能在t运行之前就调用t.join()
    当一个线程调用t.join()等待时,也会出现上文提到的wait,无法接收信号,因此如果主线程调用t.join(),将导致Ctrl-C失效。

  示例:

import threading
    import time
    
    def clock(interval):
        print "this is subThread!"
        time.sleep(interval)

    t=theading.Thread(target=clock,args=(15,))
    t.daemon=True
    t.start()
    while t.is_alive():
        time.sleep(1)

    下面的例子实现了同样的功能:
    import threading
    import time
    
    class Clock(threading.Thread):
        def __init__(self,interval):
            threading.Thread.__init__(self)
            self.daemon=True
            self.interval=interval
        def run(self):
            print "this is subThread!"
            time.sleep(self.interval)

    t=Clock(15)
    t.start()
    while t.is_alive():
        time.sleep(1)

上面的方法将线程定义为类,并且定义自己的__init__()方法,并且必须像上面那样调用基类构造函数Thread.__init__()。除此之外,需要重写run()方法,作为线程的目标函数。除了run()方法之外,重写已经定义的其他方法会出现错误。  

2. Timer对象
  class threading.Timer(interval, function, args=[], kwargs={})
  创建定时器对象,在过去interval秒时间后运行函数function。args提供传递给function的参数。在调用start()方法后会启动定时器。
  Timer对象t具有以下方法:
  (1) t.start()
    启动定时器。提供给Timer()方法的函数function将在指定的interval之后执行。
  (2) t.cancel()
    如果function函数尚未执行,取消定时器。
  示例:

import threading
    def hello():
        print "hello, world"

        t = threading.Timer(10.0, hello)
        t.start() # after 30 seconds, "hello, world" will be printed

  在等待function执行这段期间,Ctrl-C失效

3. Lock对象
  最基本的同步锁,并不属于某一个特定的线程,也就是说,一个线程设定的锁可以由另一个线程进行解锁。
  通过lock=threading.Lock()创建Lock实例:
  (1) lock.acquire([blocking])
    获取锁定,需要阻塞到锁定释放为止。
  (2) lock.release()
    释放一个锁定。当锁处于未锁定情况时,进行解锁会异常;允许其他进程解锁

4. RLock对象
  同步锁,属于某一个特定的线程,也就是说,一个线程设定的锁仅能由该线程解锁;其他进程若试图解锁会引发异常。RLock允许在同一线程中被多次acquire,而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。这条是正确的,可以开两个线程试一下!
  通过rlock=threading.RLock()创建RLock实例:
  (1) rlock.acquire([blocking])
  (2) rlock.release()

5. Semaphore对象
  信号量是一个基于计数器的同步原语,每次调用acquire()方法时此计数器减1,每次调用release()方法时此计数器加1。如果计数器为0,acquire()方法将会阻塞,直到其他线程调用release()方法为止。
  class threading.Semaphore([value])
  创建一个新的信号量。value是计数器的初始值,如果省略此参数,计数器的值将被置1.
  Semaphore实例s支持以下方法。
  (1) s.acquire([blocking])
    获取信号量。如果进入时内部计数器大于0,此方法将把它的值减1,然后立即返回。如果它的值为0,此方法将被阻塞,直到另一个线程调用release()方法为止。
  (2) s.release()
    通过将内部计数器的值加1来释放一个信号量。
  (3) BoundedSemaphore([value])
    创建一个新的信号机。它的工作方式与Semaphore完全相同,但是release()操作的次数不能超过acquire()操作的次数(Semaphore可能存在这样的隐患)

6. 实用工具函数
  (1) threading.active_count()
    返回当前活动的Thread对象数量,包括主线程
  (2) threading.current_thread()
    返回当前Thread对象,在线程内部调用。
  (3) threading.enumerate()
    返回当前活动的Thread对象列表