1. 线程进程扩展
进程创建
multi process ing
import multiprocessing
进程对象 = multiprocessing.Process(target=子进程代码入口,
args=(位置参数,...),
kwargs={"参数名":值,...},
name="子进程名",
daemon=True
)
进程对象.start()
进程对象.join() # 进程对象.terminate()
线程创建
import threading
线程对象 = threading.Thread(target=子线程代码入口,
args=(位置参数,...),
kwargs={"参数名":值,...},
name="子线程名",
daemon=True
)
线程对象.start()
线程对象.join()
多进程多线程执行顺序都是 无序的。
进程间不共享全局资源,同一个进程内部多个线程共享全局资源。
资源竞争(共享; 访问无限制)
互斥锁的作用(保证任意时刻只有一个线程能够占有锁 从而解决资源竞争)
使用
创建 互斥锁对象 = threading.Lock()
加锁 互斥锁对象.acquire() # 如果已经被别人锁住 将会一直阻塞等待
解锁 互斥锁对象.release()
优缺点 解决资源竞争 保证结果运行正确
降低多任务运行效率
容易造成死锁
daemon 进程含义
When a process exits, it attempts to terminate all of its daemonic child processes.当一个主进程退出时候 他讲会尝试终止所有的 daemon 子进程(非 daemon 子进程还可以继续运行知道完成)
daemon 线程含义
The entire Python program exits when no alive non-daemon threads are left.
os.kill(进程PID, 9) # 发送信号 9代表信号编号 绝对终止
-
死锁问题产生
原因:
多个线程相互等待对方释放响应的资源
线程在使用完互斥锁 忘记解锁 从而造成所有线程 全部都是阻塞等待
预防:
申请锁
使用
释放锁
# 自动资源管理
with 互斥锁:
使用
import threading
g_number = 0
def update_number(lock):
"""让子进程运行"""
global g_number
for i in range(1000000):
# 尝试加锁 如果没有人锁定 成功;如果有人 等待
# lock.acquire()
with lock:
g_number += 1
# 释放锁
# lock.release()
if __name__ == '__main__':
# 在门上安装一把互斥所
lock = threading.Lock()
# 1 创建一个子线程 运行 update_number
thd1 = threading.Thread(target=update_number, args=(lock,))
thd1.start()
thd2 = threading.Thread(target=update_number, args=(lock,))
thd2.start()
# 2 创建一个全局变量
# 3 让子线程修改全局变量
# 4 让主线程等待子线程退出 打印全局变量的值
# 如果这个值和子线程设置的值 说明线程间共享全局资源 ; 否则不共享
thd1.join()
thd2.join()
print("得到最终值为%s" % g_number)
- 进程线程对比
进程消耗资源更大 进程是分配资源的基本单位<稳定性 CPU密集型-数学计算> 可用多核
线程消耗资源更少 <轻量级 IO密集型-爬虫>
系统自带的原生线程 可以用多核
CPython 解释器产生的多线程(存在GIL 全局解释器锁 为了防止 CPython 中的多线程 同时访问和修改解释器内部的全局资源 ) 导致在解释器内部任意时间只有一个线程在运行 不能使用多核
google浏览器新开标签就会创建一个进程 火狐浏览器新开一个标签就会创建新的线程