参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017627212385376
进程
在操作系统中一个任务
对应一个进程
,如打开了word就启动了一个word进程
线程
一个进程
下可以有多个线程
但至少一个线程
,
Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
同时执行多个任务
- 多进程模式:启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
- 多线程模式:启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
多进程 + 多线程模式 :启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。
multiprocessing 跨平台的多进程模块
# multiprocessing 中 使用 Process 代表一个进程对象
from multiprocessing import Process
import os
# 子进程运行的代码;
# proc_name: str ,表示 形参proc_name 需要是str类型 :
# https://docs.python.org/zh-cn/3.7/library/typing.html?highlight=typing#module-typing
def run_proc(proc_name: str):
print(f'子进程运行,进程名称 { proc_name },其进程ID为:{ os.getpid() }')
def run_proc1():
print(f'子进程运行,其进程ID为:{ os.getpid() }')
def run_proc2(name: str, now: str):
print(f'子进程运行,进程名称 { name },其进程ID为:{ os.getpid() }, 当前时间 { now }')
if __name__ == '__main__':
print(F"主进程ID:{ os.getpid() }")
# 创建一个进程, target=需执行的函数, args=(需执行的函数参数, ), 可以是多个,1个也需要元组形式传递参数
p = Process(target=run_proc, args=('测试进程', ))
# 需执行函数无参数时,创建进程
p1 = Process(target=run_proc1)
p2 = Process(target=run_proc2, args=('name', 'fff', ))
print("子进程将启动!")
# start 方法启动进程
p.start()
p1.start()
p2.start()
# join 方法等待子进程结束后继续往下运行
p.join()
p1.join()
p2.join()
print('子进程结束')
Pool:进程池,批量创建进程
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print(f'任务:{ name }({ os.getpid()})运行')
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print(f'任务 { name } 运行耗时 { end-start: .2f} 秒')
if __name__ == '__main__':
print(f'主进程{ os.getpid() }')
# 创建4个进程: Pool的默认大小是CPU的核心数,如果是8核cpu,你要提交至少9个线程才能看到效果
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('等待所有子进程运行完成')
# 执行该方法后不能继续添加新的Process
p.close()
# 等待所有子进程执行完毕
p.join()
print('所有进程运行完毕!')
运行结果:
/Users/zy7y/PycharmProjects/demo/venv/bin/python /Users/zy7y/PycharmProjects/demo/pool_demo.py
主进程1893
等待所有子进程运行完成
任务:0(1894)运行
任务:1(1895)运行
任务:2(1896)运行
任务:3(1897)运行
任务 1 运行耗时 0.36 秒
任务:4(1895)运行
任务 2 运行耗时 1.08 秒
任务 0 运行耗时 2.77 秒
任务 3 运行耗时 2.81 秒
任务 4 运行耗时 2.45 秒
所有进程运行完毕!
结果解读:
任务0
,1
,2
,3
是立刻执行的,任务4
是等前面某个任务完成后才执行,这是因为Pool的默认大小在本机是4,因此最多同时拥有4个进程
子进程(暂未理解)
subprocess
实现方便启动一个子进程,控制其输入和输出
https://www.liaoxuefeng.com/wiki/1016959663602400/1017628290184064
进程间通信
Python的
multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据。
import os
import random
import time
from multiprocessing import Process, Queue
# 写数据进程执行的代码
def write(q):
print(f"用来写入的进程{os.getpid()}")
for value in ['A', 'B', 'C']:
print(f'把{ value }放入Queue(队列)中')
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码
def read(q):
print(f'用来读取的进程{os.getpid()}')
while True:
value = q.get(True)
print(f'从队列中获取 {value}')
if __name__ == '__main__':
# 主进程创建Queue,并传递给各个子进程
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw, 写入:
pw.start()
# 启动子进程pr, 读取:
pr.start()
# 等待pw结束
pw.join()
# pr进程是个死循环,无法自己结束,只能强行终止:
pr.terminate()
运行结果:
/Users/zy7y/PycharmProjects/demo/venv/bin/python /Users/zy7y/PycharmProjects/demo/queue_demo.py
用来写入的进程2226
把A放入Queue(队列)中
用来读取的进程2227
从队列中获取 A
把B放入Queue(队列)中
从队列中获取 B
把C放入Queue(队列)中
从队列中获取 C
Process finished with exit code 0