Python 进阶系列笔记文章链接:
Python 进阶学习笔记之一:内置常用类型及方法
Python 进阶学习笔记之二:常用数据类型(上)
Python 进阶学习笔记之三:常用数据类型(下)
Python 进阶学习笔记之四:高效迭代器工具
Python 进阶学习笔记之五:异步 IO
Python 进阶学习笔记之六:多线程编程
Python 进阶学习笔记之七:互联网支持
Python 进阶学习笔记之八:面向对象高级编程
Python 进阶学习笔记之九:IO 编程
Python 进阶学习笔记之十:一般加密支持
Python 进阶学习笔记之十一:日志支持
Python 进阶学习笔记之十二:数据压缩与归档
1. 多线程编程 - threading
在多核服务器上,多线程充分利用多核特性提升效率是很普遍的做法,threading 模块就提供了支持多线程编码的高级 API。threading 模块是在较低级的模块 _thread 基础上建立较高级的线程接口,推荐在 3.7 版本后使用本模块构建普通多线程程序。如果你想让你的应用更好的利用多核计算机的计算性能,推荐你使用 multiprocessing
模块或者 concurrent.futures.ProcessPoolExecutor
类。但是如果你想同时运行多个I/O绑定任务,线程仍然是一个合适的模型。
先代码示例最基本用法:
import threading
import time
local_param = threading.local() # 线程 local 变量是一种能存储当前线程变量的一种容器类型,专门用于多线程变量存储
def do_somthing():
local_param.name = threading.current_thread().getName() # 当前代码示例中,可以使用此方法获取当前线程的名称
print(f"{local_param.name} is doing something...")
time.sleep(1)
print("over")
mt = threading.Thread(target=do_somthing, name="n1") # 一种线程实例话方法
mt2 = threading.Thread(target=do_somthing, name="n2")
mt.start()
mt2.start()
# 输出
n1 is doing something...
n2 is doing something...
over
over
# 用法2
local_param = threading.local()
class MyThread(threading.Thread):
def run(self):
name = self.name # 继承 Thread 的方式实现一个线程,可以直接取线程名称
local_param.name = name
print(f"{local_param.name} is doing something...")
time.sleep(1)
print(f"{name} is over")
t1 = MyThread()
t2 = MyThread()
t1.setName("t1")
t2.setName("t2")
t1.start()
t2.start()
# 输出
n1 is doing something...
n2 is doing something...
over
over
上面示例中就启动了两个线程,具体业务可以拿上面两个写法进行扩展了。下面具体讲解一下原生 线程的一些同步操作工具和语法。
查看模块 threading 的源码文件,查看模块注释可以知道,该模块的设计基于 Java 的线程模型,Python 的 Thread 类只是 Java 的 Thread 类的一个子集;目前还没有优先级,没有线程组,线程还不能被销毁、停止、暂停、恢复或中断。
1.1 线程本地数据
线程本地数据是特定线程的数据。管理线程本地数据,只需要创建一个 local (或者一个子类型)的实例并在实例中储存属性:
mydata = threading.local()
mydata.x = 1
在不同的线程中,实例的值会不同,上面的简例中已经有了基本应用。
1.2 线程对象
线程对象通过 threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
进行实例或者继承它在进行实例,实例后需要调用 start()
方法来启动线程,直到线程内部的 run()
方法执行完成,它都处于 ‘活跃’ 状态,可以用 is_alive()
方法用于检查线程是否存活。Python 3.3 新加入的 daemon
参数,用来标记一个线程是否是守护线程。
1.3 上下文管理
上下文管理,也就是 with 语句,在这个模块提供的带有 acquire() 和 release() 方法的对象,都可以被用作 with 语句的上下文管理器,当进入语句块时 acquire() 方法会被调用,退出语句块时 release() 会被调用。因此,以下片段:
with some_lock:
# do something...
相当于:
some_lock.acquire()