进程
程序与进程的区别
程序:代码 二进制 exe 静态
进程:程序运行后 资源+代码 动态
进程的流程:
写时拷贝:
进程中,子进程修改时拷贝影响的代码资源,不修改时不拷贝仅运行
创建进程流程:
# 导入进程模块
import multiprocessing
# 创建一个进程的实力对象
P = multiprocessing.Process(target=func_name[,args=(元组), kwargs={字典}])
# 创建并启动进程
p.start()
p.join(5)
创建进程示例:
import time
import multiprocessing
def test1():
while True:
print("---1---")
time.sleep(1)
def test2():
while True:
print("---2---")
time.sleep(1)
def main():
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
p1.start()
p2.start()
if __name__ == '__main__':
main()
注:
- 先有主进程,后有子进程,但之后谁先进行不一定,最后主进程收尾
主线程结束,所有子线程结束; - 主进程结束,不影响子进程,且终端也不再能控制子进程;父进程被结束后分配继父进程,继父进程被结束后,子进程成为僵尸变量,且系统崩溃。
获取pid:
- 当前进程pid os.getpid
- 父进程pid os.getppid
传递参数:
注:
- 先有进行再有线程,线程依赖于进程
- 主进程一定有一个主线程
进程套线程
(类比树 主干主进程 枝干子进程 叶柄主线程 叶片子线程) - 进程:多份资源,各一份执行,是资源分配的单位
- 线程:一份资源,多份执行,是操作系统调动的单位 资源占用少 推荐
进程间通信:
文件 储存中
socket 网络中
Queue队列 内存中 解耦 (multiprocessing)
Queue队列完成进程间通信流程:
# 创建一个队列
q = multiprocessing.Queue(3) # 3代表队列中最多可以接收三条消息
# 向队列中添加数据
q.put(data)
# 从队列中取数据
q.get()
# 判断队列中是否为空
q.empty()
# 判断队列中是否已满
q.full()
注意:如果是通过进程池创建的进程,那么队列的使用要用
multiprocessing.Manager().Queue()的方式,否则会报错。
Queue创建示例:
import multiprocessing
def download_from_web(q):
"""下载数据"""
# 模拟从网上下载的数据
data = [11,22,33,44]
# 向队列中写入数据
for temp in data:
q.put(temp)
print("--下载器已完成下载并存入队列中--")
def analysis_data(q):
"""数据处理"""
waitting_analysis_data = list()
# 从队列中获取数据
while True:
data =q.get()
waitting_analysis_data.append(data)
if q.empty():
break
# 模拟数据处理
print(waitting_analysis_data)
def main():
# 创建一个队列
q = multiprocessing.Queue()
# 创建多个进程,将队列的引用当做实参进行传参
p1 = multiprocessing.Process(target=download_from_web,args=(q,))
p2 = multiprocessing.Process(target=analysis_data,args=(q,))
p1.start()
p2.start()
if __name__ == '__main__':
main()
进程池 pool
进程池创建流程:
# 导入进程池模块
from multiprocessing import Pool
# 定义进程池,最大进程池最大数
po = Pool(3)
# 通过进程池调用目标 apply_async非阻塞,不会等待子进程结束;apply阻塞,会等待子进程结束
po.apply_async(要调用的目标,(传递给目标的参数元祖,))
# 关闭进程池
Po.close()
# 等待进程池执行完毕
po.join()
注:
- 主进程不会等待进程池进行完,需添加join();
进程池若出现异常,不会显示异常。 - 通过进程池调用目标 apply_async非阻塞,不会等待子进程结束;apply阻塞,会等待子进程结束
进程池创建演示:
from multiprocessing import Pool
import os, time, random
def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d" % (msg, os.getpid()))
# random.random()随机生成0~1之间的浮点数
time.sleep(random.random() * 2)
t_stop = time.time()
print(msg, "执行完毕,耗时%0.2f" % (t_stop - t_start))
if __name__ == '__main__':
po = Pool(3) # 定义一个进程池,最大进程数3
for i in range(0, 10):
# Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
# 每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker, (i,))
print("----start----")
po.close() # 关闭进程池,关闭后po不再接收新的请求
po.join() # 等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
进程与线程的区别
区别:线程占用资源小,共享全局变量;进程占用资源多,每个子进程多占用一部分资源,但不共享全局变量。
优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。