本文章使用 python3.7,详情可查看官方内容:
https://docs.python.org/3.7/library/threading.html#module-threading
threading 使用的是高等级api,与之对应的是 _thread ,它是低等级的api,提供更复杂更底层的使用。
threading
threading.
active_count
()
返回所有存活的线程对象数量,这个数量等于 enumerate()
获取到的 list 长度
threading.
current_thread
()
返回目前的线程对象,对应于调用者的线程控制。如果调用者的线程控制没有通过 threading 创建,将会返回功能受限的虚拟线程对象。
threading.
get_ident
()
返回当前线程的识别码。它是非零整数,有各种用途,比如索引线程特有的数据目录。当线程退出,创建新的线程时,线程识别码可能被再次使用。
threading.
enumerate
()
返回所有存活线程的对象列表,包括守护线程,被 current_thread()
创建的虚拟线程对象和主线程。不包括已经结束的线程和没有启动的线程。
threading.
main_thread
()
返回主线程对象,通常情况下,主线程是启动 python 解释器的那个线程。
threading.
settrace
( func )
为启动的线程设置追踪函数。对于每一个线程,在调用 run 方法之前,会把 func 参数传递给 sys.settrace()
。
threading.
setprofile
( func )
为所有线程设置一个轮廓函数。对于每一个线程,在调用 run 方法之前,会把 func 参数传递给 sys.setprofile()
。
threading.
stack_size
([ size ])
返回线程的栈容量。可选参数 size 指定随后创建的线程栈大小,只能是 0 或者正数值(至少32,768,即32KiB)。如果没指定 size ,默认使用 0 。如果不能修改线程的栈容量,会抛出 RuntimeError
异常。如果指定非法的参数,会抛出 ValueError
异常并且栈的大小不会被更改。栈的最小值为32 KiB,用来保证解释器有足够的栈空间。 请注意,某些平台可能会对栈容量有特定限制。
该功能可在 windows ,支持 POSIX 线程的系统上使用。
threading.
TIMEOUT_MAX
函数被阻塞的最大时间( Lock.acquire()
, RLock.acquire()
, Condition.wait()
, etc.),如果指定的超时值大于此值,将引发 OverflowError
异常。
threading 模块借鉴了 java 线程模块, java 对每个对象都使用锁和条件变量,但 python 中是独立的对象。Python 的线程类支持 java 线程类的所有动作。目前没有优先级,没有线程组,并且无法销毁,停止,挂起,恢复或中断线程。 Java Thread 类的静态方法在实现后会映射到模块级函数。
线程局部数据
线程局部数据是每个线程独有的数据,可以创建一个 local
(or a subclass) 实例,然后这个实例中存数据,比如下面代码:
mydata = threading.local()
mydata.x = 1
不同线程的实例值可以不同,更多细节可参考 _threading_local
模块。
线程对象
Thread
类表示在单独的控制线程中运行的活动。有两种活动定义方式:向构造器传递一个可被调用的对象或者在子类中重写 run()
方法。只要创建好线程对象,就可以调用线程的 start()
方法启动活动。它会在每个独立的控制线程中调用 run()
方法。一旦线程启动了活动,那么它就处于存活状态,当 run()
方法终止运行(可能正常退出,也可能抛出异常)时,就会退出存活状态,可以用 is_alive()
方法查看线程是否处于存活状态。
线程可以调用 join()
方法,它将阻塞此线程,直到其他调用 join()
方法的线程结束运行。
多线程代码及实现
不使用任何多线程时,代码会执行 6s 后结束;
"""
This module provides multithreading example
"""
from time import sleep, ctime
def loop0():
"""sleep 4s and print time"""
print('start loop0 at ' + ctime())
sleep(4)
print('end loop0 at ' + ctime())
def loop1():
"""sleep 2s and print run time"""
print('start loop1 at ' + ctime())
sleep(2)
print('end loop1 at ' + ctime())
def main():
"""invoking loop0 and loop1 , print time"""
print("all start at" + ctime())
loop0()
loop1()
print("all end at " + ctime())
if __name__ == '__main__':
main()
使用 _thread 方式,利用 _thread.start_new_thread()
函数创建子线程,并使用 sleep(6) 保持主线程不退出:
"""
This module provides multithreading example
"""
from time import sleep, ctime
import _thread
def loop0():
"""sleep 4s and print time"""
print('start loop0 at ' + ctime())
sleep(4)
print('end loop0 at ' + ctime())
def loop1():
"""sleep 2s and print time"""
print('start loop1 at ' + ctime())
sleep(2)
print('end loop1 at ' + ctime())
def main():
"""using _thread invoke loop0 and loop1 , print time"""
print("all start at" + ctime())
_thread.start_new_thread(loop0, ())
_thread.start_new_thread(loop1, ())
sleep(6)
print("all end at " + ctime())
if __name__ == '__main__':
main()
使用改进的 _thread ,利用 _thread 锁实现主线程自动监视子线程是否解锁:
"""
This module provides multithreading example
"""
from time import sleep, ctime
import _thread
LOOPS = [4, 2]
def loop(nloop, nsec, lock):
"""
Sleep time according to parameters
:param nloop: thread name
:param nsec: sleep time
:param lock: using lock
:return: pass
"""
print("start loop", nloop, "at" + ctime())
sleep(nsec)
print('loop', nloop, "at" + ctime())
lock.release()
def main():
"""
setting lock for every thread
invok loop according to loops
:return: pass
"""
print("starting at" + ctime())
locks = []
nloops = range(len(LOOPS))
for i in nloops:
lock = _thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in nloops:
_thread.start_new_thread(loop, (i, LOOPS[i], locks[i]))
for i in nloops:
while locks[i].locked():
pass
print("all stop")
if __name__ == '__main__':
main()
其它方法(todo 代码 PEP8 格式优化, todo 解释)。
threading