Python - threading
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 线程。
如果daemon
为True
,则创建的线程为 daemon 线程,否则,继承创建线程的daemon
属性。
- start()
启动线程 - run()
线程执行的主要方法,方法里面实际上是调用了target
参数的函数。所以线程的执行函数可以通过target
参数传进来给run()
,也可以重写run()
方法。 join(timeout=None)
阻塞当前程序,一个线程可以被join()
多次。timeout
:None
,会一直阻塞,直到全部被join()
的线程执行完,才继续执行主体下面的代码。>=0
的 float 时间(seconds):阻塞一定时间。0
,即不阻塞。注意,经测试总阻塞时间为所有线程timeout
的时间总和。1
2
3
4thread_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
5thread_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.Thread
传target
参数1
2
3
4
5
6def 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
6class 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.
原始锁不属于任何线程。一把原始锁只有两种状态:
locked
和unlocked
。刚创建的锁属于unlocked
状态。
threading.Lock()
用于生成原始锁的工厂方法。
acquire(block=True, timeout=-1)
获取一把线程锁 (即把锁从unlocked
状态设置为locked
状态)。返回True/False
。block
:True/False
,设置申请获取线程锁的模式:阻塞(True
)或非阻塞(False
)。True
: 当为阻塞模式时,会一直阻塞直到获取到线程锁为止,然后返回True
。所以,在这个模式当一个线程多次获取线程锁的时候会造成死锁。1
2
3lock = 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
4rlock = 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
可重入锁会立即成功返回。
可重入锁的
acquire
和release
都必须要在同一个线程中,即一个线程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
19class 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 | import time |