Python 标准库之 threading (线程并行)
date
Mar 24, 2020
slug
5589750164580352
status
Published
tags
Python
summary
type
Post
示例
返回活跃线程的数量
In [1]: import threading In [2]: threading.active_count() Out[2]: 22In [3]: len(threading.enumerate()) Out[3]: 22
返回活跃线程列表
In [1]: import threading In [2]: threading.enumerate() Out[2: [<_MainThread(MainThread, started 3744)>, <HistorySavingThread(IPythonHistorySavingThread, started 9356)>, <Thread(ThreadPoolExecutor-0_0, started daemon 6552)>, <Thread(ThreadPoolExecutor-0_1, started daemon 9492)>, <Thread(ThreadPoolExecutor-0_2, started daemon 8740)>, <Thread(ThreadPoolExecutor-0_3, started daemon 4128)>, <Thread(ThreadPoolExecutor-0_4, started daemon 288)>, <Thread(ThreadPoolExecutor-0_5, started daemon 2804)>, <Thread(ThreadPoolExecutor-0_6, started daemon 5848)>, <Thread(ThreadPoolExecutor-0_7, started daemon 9608)>, <Thread(ThreadPoolExecutor-0_8, started daemon 6348)>, <Thread(ThreadPoolExecutor-0_9, started daemon 7156)>, <Thread(ThreadPoolExecutor-0_10, started daemon 4268)>, <Thread(ThreadPoolExecutor-0_11, started daemon 7364)>, <Thread(ThreadPoolExecutor-0_12, started daemon 7532)>, <Thread(ThreadPoolExecutor-0_13, started daemon 5888)>, <Thread(ThreadPoolExecutor-0_14, started daemon 364)>, <Thread(ThreadPoolExecutor-0_15, started daemon 5816)>, <Thread(ThreadPoolExecutor-0_16, started daemon 9636)>, <Thread(ThreadPoolExecutor-0_17, started daemon 6756)>, <Thread(ThreadPoolExecutor-0_18, started daemon 10080)>, <Thread(ThreadPoolExecutor-0_19, started daemon 7264)>]
创建一个线程
In [1]: import threading In [2]: thread = threading.Thread() In [3]: thread Out[3]: <Thread(Thread-1, initial)>
为线程绑定任务
In [1]: import threading In [2]: thread = threading.Thread() In [3]: def f1(): ...: print("Her") ...: In [4]: thread.target = f1 In [5]: thread.target Out[5]: <function __main__.f1()>
或
In [1]: import threading In [2]: def f1(): ...: print("Her") ...: In [2]: thread = threading.Thread(target=f1)
为线程任务传递参数
In [1]: import threading In [2]: def f1(i): ...: print("Her"+str(i)) ...: In [2]: thread = threading.Thread(target=f1, args=(666,))
运行线程
In [1]: import threading In [2]: def f1(i): ...: print("Her"+str(i)) ...: In [2]: thread = threading.Thread(target=f1, args=(666,)) In [3]: thread.start() Her666
注意:In [1]: thread.run() Her666
- start() 方法是启动一个子线程
- run() 方法并不启动一个新线程,而是在主线程中调用了任务函数。
- start() 它在一个线程里最多只能被调用一次。
阻塞调用的线程 (守护线程)
不使用
join() :import threading import time def f1(): for i in range(2): print("thread1", time.ctime()) time.sleep(1) thread1 = threading.Thread(target=f1) thread1.start() print("done")
输出:
thread1 Wed Mar 18 18:52:23 2020 done thread1 Wed Mar 18 18:52:24 2020
使用
join() :import threading import time def f1(): for i in range(2): print("thread1", time.ctime()) time.sleep(1) thread1 = threading.Thread(target=f1) thread1.start() thread1.join() print("done")
输出:
thread1Wed Mar 18 18:55:55 2020 thread1Wed Mar 18 18:55:56 2020 done
使用
join() 会将调用这个线程的主线程阻塞,等待当前线程终止后才将控制权交还给主线程。多线程访问临界值
import threading import time a = 0def f1(): global a t = a + 1 print(t) time.sleep(1) # 模拟修改变量值的时间过程 a = t threads = [threading.Thread(target=f1) for _ in range(5)] for _ in threads: _.start()
输出:
1 1 1 1 1
CPU 太快了,导致
time.sleep(1) 休眠没有结束就跑完所有线程,此时线程获取到 a 的值都是 0线程锁
# 创建线程锁lock = threading.Lock() # 获得锁lock.acquire() # 释放锁lock.release()
为临界资源加锁:
import threading import time lock = threading.Lock() a = 0def f1(): global a lock.acquire() t = a + 1 print(t) time.sleep(1) # 模拟修改变量值的时间过程 a = t lock.release() threads = [threading.Thread(target=f1) for _ in range(5)] for _ in threads: _.start()
输出:
1 2 3 4 5
参考
threading.active_count() : 返回当前活跃的线程对象的数量
threading.current_thread() : 返回当前线程对象
threading.excepthook(args, /) : 处理 Thread.run() 未捕获的异常
threading.get_ident() : 返回当前线程的索
threading.get_native_id() : 返回内核分配给当前线程的原生集成线程 ID
threading.enumerate() : 以列表形式返回当前所有存活的 Thread 对象
threading.main_thread() : 返回主 Thread 对象
threading.settrace(func) : 为所有 threading 模块开始的线程设置追踪函数
threading.setprofile(func) : 为所有 threading 模块开始的线程设置性能测试函数
threading.stack_size([size]) : 返回创建线程时用的堆栈大小
threading.TIMEOUT_MAX : 阻塞函数( Lock.acquire(), RLock.acquire(), Condition.wait(), …)中形参 timeout 允许的最大值threading.local() :创建本地线程数据线程对象
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) : 创建线程对象参数 | 说明 |
group | group 应该为 None;为了日后扩展 ThreadGroup 类实现而保留 |
target | 用于 run()方法调用的可调用对象 |
name | 线程名称 |
args | 调用目标函数的参数元组 |
kwargs | 用目标函数的关键字参数字典 |
daemon | 是否为守护模式,默认值 None 为线程将继承当前线程的守护模式属性 |
start() :开始线程活动。
run() :代表线程活动的方法。 标准的 run() 方法会对作为 target 参数传递给该对象构造器的可调用对象(如果存在)发起调用,并附带从 args 和 kwargs 参数分别获取的位置和关键字参数
join(timeout=None) : 等待,直到线程终结。
name :只用于识别的字符串。
getName(),setName() :获取/设置 name 的值。
ident :这个线程的 ‘线程标识符’
native_id :该线程的当前线程ID。
is_alive() :返回线程是否存活。
daemon :一个表示这个线程是(True)否(False)守护线程的布尔值。
isDaemon(),setDaemon() :获取/设置 name的值。锁对象
threading.Lock() :创建所。
acquire(blocking=True, timeout=-1) :可以阻塞或非阻塞地获得锁。
release() :释放一个锁。
locked() :如果获得了锁则返回真值。