threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

  • group:
  • target: 线程的执行方法,在 run() 方法内被调用。
  • name: 线程名称
  • args: 传给线程执行方法 (target) 的参数,默认 ()。位置参数和关键字参数都可以传,不过一定要注意顺序,传一个参数的时候要注意 (a,)
  • kwargs: 传给线程执行方法 (target) 的参数,只能够传关键字参数,默认 {}
  • daemon: Python3.3 新增参数。可以通过 daemon 参数来定义创建的线程是否为 daemon 线程。
    如果 daemonTrue,则创建的线程为 daemon 线程,否则,继承创建线程的 daemon 属性。
  • start()

    启动线程
  • run()

    线程执行的主要方法,方法里面实际上是调用了 target 参数的函数。所以线程的执行函数可以通过 target 参数传进来给 run(),也可以重写 run() 方法。
  • join(timeout=None)

    阻塞当前程序,一个线程可以被 join() 多次。timeout

    • None,会一直阻塞,直到全部被 join() 的线程执行完,才继续执行主体下面的代码。
    • >=0 的 float 时间(seconds):阻塞一定时间。0,即不阻塞。注意,经测试总阻塞时间为所有线程 timeout 的时间总和。
      1
      2
      3
      4
      thread_list = [threading.Thread(target=xxx) for _ in range(5)]  # 创建 5 个线程
      map(lambda t: t.start(), thread_list) # 启动线程
      map(lambda t: t.join(timeout=1), thread_list) # 设置阻塞模式
      print('END'.center(100, '-'))

    创建线程,并且设置了每个线程阻塞 1s。所以 print('END'.center(100, '-')) 语句会在全部线程执行完或者 5s 之后才去执行。

  • name

    获取或设置线程名称。

  • ident

    线程标识符,非零整数。
  • daemon

    获取或设置线程 daemon 属性,设置 daemon 属性要在 start() 之前才会生效。如果不设置,会继承创建线程的程序的 daemon 属性值。如果线程为 daemon 线程,则主程序结束退出的时候,daemon 线程也会结束。

    1
    2
    3
    4
    5
    thread_list = [threading.Thread(target=xxx) for _ in range(5)]  # 穿件 5 个线程
    map(lambda t: setattr(t, 'daemon', True), thread_list)
    map(lambda t: t.start(), thread_list) # 启动线程
    time.sleep(5)
    exit()

    程序创建了 5 个线程,并且都是 daemon 线程。所以,无论线程有没有执行完,主程序执行完 (5s后),所有线程也会退出。

注意:因为 daemon 线程是会随着主程序的退出而强制结束的,所以,当 daemon 线程的一些操作可能会得不到安全的结束 (如:操作文件的时候)。

  • is_alive()

    返回当前线程是否存活。

threading 模块创建线程有两种方法:

  • 方法一,通过 threading.Threadtarget 参数

    1
    2
    3
    4
    5
    6
    def thread_run():
    """The thread mainly run function."""
    pass
    thread = threading.Thread(target=thread_run)
    thread.start()
    thread.join()
  • 方法二,通过继承 threading.Thread 对象,重写 run 方法

    1
    2
    3
    4
    5
    6
    class SubThread(threading.Thread):
    def run(self):
    pass
    thread = SubThread()
    thread.start()
    thread.join()

threading 模块其它常用函数

  • threading.current_thread()

    返回当前的 Thread 对象。

  • threading.enumerate()

    返回当前存活的 Thread 对象的列表。注意:返回的 Thread 对象包括后台线程。如:<_MainThread>///, etc.

  • threading.active_count()

    放回当前存活的 Thread 对象数量。注意:该数量包括了后台线程,其实就是 enumerate() 列表的数量。

  • threading.get_ident()

    Python3.3 新增,其实就是 Thread 对象的 ident 属性。

  • threading.main_thread()

    Python3.4 新增,返回主线程。


A primitive lock is a synchronization primitive that is not owned by a particular thread when locked. In Python, it is currently the lowest synchronization primitive available, implemented directly by _thread extension module.

原始锁不属于任何线程。一把原始锁只有两种状态:lockedunlocked。刚创建的锁属于 unlocked 状态。

threading.Lock()

用于生成原始锁的工厂方法。

  • acquire(block=True, timeout=-1)

    获取一把线程锁 (即把锁从 unlocked 状态设置为 locked 状态)。返回 True/False

    • block: True/False,设置申请获取线程锁的模式:阻塞(True)或非阻塞(False)。

      • True: 当为阻塞模式时,会一直阻塞直到获取到线程锁为止,然后返回 True。所以,在这个模式当一个线程多次获取线程锁的时候会造成死锁。

        1
        2
        3
        lock = threading.Lock()
        lock.acquire() # 申请线程锁
        lock.acquire() # 再次申请线程锁的时候会造成死锁
      • False: 当为非阻塞模式时,如果没有获取到线程锁会立即返回 False

    • timeout: Python3.2 新增,当 block=True 时有效,设置阻塞的超时时间。
  • release()

    释放线程锁 (即把锁设置为 unlocked 状态),没有返回值。因为线程锁不是属于某个专属线程的,所以,释放锁 (release()) 的时候不一定要在上锁的那个线程。

release 一把 unlocked 状态的锁的时候会引起 release unlocked lock 错误。

threading 模块中所有包含 acquire()release() 的对象,如:Lock(), RLock(), Condition(), Semaphore() 都可以用上下文管理器 with 语句来操作。

1
2
3
4
rlock = threading.RLock()
with rlock:
with rlock:
...


A reentrant lock is a synchronization primitive that may be acquired multipart times by the same thread.

可重入锁可以被同一个线程多次获取。可重入锁有 “owning thread” 的概念,即当一个线程获取到可重入锁的时候,这把锁是属于这个线程的。

当一个线程获取到可重入锁的时候,再次 acquire 可重入锁会立即成功返回。

可重入锁的 acquirerelease 都必须要在同一个线程中,即一个线程 acquire 了多少次可重入锁,就必须 release 多少次。

Python 的 RLock() 其实就是在 Lock() 上做了一层封装,在 RLock() 对象里面添加了一个 __owner__count 分别用来记录可重入锁的所属者和 acquire 层数。

threading.RLock()

用于生成可重入锁的工厂方法。

  • acquire(blocking=True, timeout=-1)

    threading.Lock.acquire()

  • release()

    减少可重入锁的递归 acquire 层数,当对应最后一个 acquire 时,释放可重入锁 (即把锁设置为 unlocked 状态),没有返回值。

线程对可重入锁是有一个拥有概念的,线程的每个 acquire 都必须在同一个线程 release

release 一把 unlocked 状态的锁的时候会引起 release unlocked lock 错误。

threading.RLock 使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class test(object):
def __init__(self):
self.val = []
self.rlock = threading.RLock()

def func(self):
self.rlock.acquire()
self.val.append(1)
self.rlock.release()

def run(self):
self.rlock.acquire()
self.func()
self.rlock.release()

def main(self):
thread_list = [threading.Thread(target=self.func) for _ in range(5)]
map(lambda t: t.start(), thread_list)
map(lambda t: t.join(), thread_list)

线程使用了可重入锁来保证列表的线性安全,如果将 func()run() 里面的 RLock() 换成 Lock() 就会造成线程死锁。

threading.Event()

线程间事件管理器。实际上就是线程之间的一个共享标记变量,线程可以任意改变这个变量的值(True/False),其它线程根据变量的值等待或做其它事情。

  • is_set()

    如果标志为True,则返回True

  • set()

    设置标志为True

  • clear()

    设置标志为False

  • wait(timeout=None)

    阻塞,直到标志为True,或者超时timeout。默认timeout=None,表示会一直阻塞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import time
import threading

def thread_run(n, event):
while True:
print(n)
n -= 1
time.sleep(1)
if n <= 0:
break
# finish, set the flag to True
event.set()

event = threading.Event()
thread = threading.Thread(target=thread_run, args=(10, event))
thread.daemon = True
thread.start()
event.wait(timeout=5) # the main process will wait and block 5 seconds
print('hello') # after 5 seconds