- 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kun1280437633/article/details/80321342
1. 进程
程序:例如xxx.py这是程序,是一个静态的
进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程也是可以的
2. 进程的状态
工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
- 就绪态:运行的条件都已经慢去,正在等在cpu执行
- 执行态:cpu正在执行其功能
- 等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
3.进程的创建-multiprocessing
multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情
代码:
import multiprocessing # 1.导入模块
import os # 导入 os 模块
import time
def work1():print('work1的 pid:', os.getpid()) # getpid 获取当前进程的 pid
print('work1的 ppid:', os.getppid()) # getppid 获取 父进程 pid
for i in range(5):
print('正在搬砖:', i)
time.sleep(1)
def work2():
print('work2的 pid:', os.getpid())
print('work2的 ppid:', os.getppid())
for i in range(5):
print('正在扫地:', i)
time.sleep(1)
def main():
"""使用进程完成多任务效果"""
print('主进程的 pid:', os.getpid())
print('主进程的 ppid:', os.getppid())
t1 = multiprocessing.Process(target=work1) # 2.创建对象
t2 = multiprocessing.Process(target=work2)
t1.start() # 3.开启进程
t2.start()
if __name__ == '__main__':
main()
注意:
(1)进程的切换是随机的
(2)主进程会等待子进程结束
(3)主进程死亡会导致所有子进程死亡
4、让进程顺序执行
代码:
import multiprocessing
import os # 1.导入 os 模块
import time
def work1():
for i in range(5):
print('正在搬砖:', i)
time.sleep(1)
def work2():
for i in range(5):
print('正在扫地:', i)
time.sleep(1)
def main():
"""使用进程完成多任务效果"""
t1 = multiprocessing.Process(target=work1)
t2 = multiprocessing.Process(target=work2)
t1.start()
# time.sleep(7)
t1.join() # 冻结代码,直到 t1 运行结束
t2.start()
if __name__ == '__main__':
main()
5、进程间不能使用传参和全局变量共享数据
代码1:
import multiprocessing
def work1(ls, *args, **kwargs):
print(ls, args, kwargs)
def main():
"""主进程向子进程传参"""
ls = [11,22]
x = 100
y = 200
z = 300
p1 = multiprocessing.Process(target=work1, args=(ls, x, y, z), kwargs={'name':'zs'}) # 主进程可以传递数据给子进程
p1.start()
if __name__ == '__main__':
main()
结果:
[11, 22] (100, 200, 300) {'name': 'zs'}
代码2:
import multiprocessing
def work1(ls):
print('work1--', ls)
ls.append(55)
print('work1--', ls)
def work2(ls):
print('work2--',ls)
def main():
"""主进程向子进程传参"""
ls = [11,22]
p1 = multiprocessing.Process(target=work1, args=(ls, ))
p2 = multiprocessing.Process(target=work2, args=(ls, ))
p1.start()
p1.join()
p2.start()
if __name__ == '__main__':
main()
结果:
work1-- [11, 22]
work1-- [11, 22, 55]
work2-- [11, 22]
代码3:
import multiprocessing
def work1():
print('work1--', ls)
ls.append(55)
print('work1--', ls)
def work2():
print('work2--', ls)
ls = [11, 22] # 由于子进程的数据复制,无法使用全局变量在多个进程间共享数据
def main():
"""主进程向子进程传参"""
p1 = multiprocessing.Process(target=work1)
p2 = multiprocessing.Process(target=work2)
p1.start()
p1.join()
p2.start()
if __name__ == '__main__':
main()
结果:
work1-- [11, 22]
work1-- [11, 22, 55]
work2-- [11, 22]
6、进程间通信使用Queue
代码:
import multiprocessing
def work1(q):
q.put(11) # p1进程放入数据
print('work1 放入数据')
def work2(q):
data = q.get() # p2 进程可以取出数据
print('work2 取出数据:', data)
def main():
"""创建两个进程,一个负责向队列放入数据,另一个负责从队列取出数据"""
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=work1, args=(q,))
p2 = multiprocessing.Process(target=work2, args=(q,))
p1.start()
# p1.join()
p2.start()
if __name__ == '__main__':
main()
结果:
work1 放入数据
work2 取出数据: 11
代码2;
import multiprocessing
def work1(q):
for i in range(1000):
q.put(i) # p1进程放入数据
print('work1 放入数据')
def work2(q):
while True:
data = q.get() # p2 进程可以取出数据
print('work2 取出数据:', data)
# if q.empty(): # 当队列没有数据则退出
# break
def main():
"""创建两个进程,一个负责向队列放入数据,另一个负责从队列取出数据"""
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=work1, args=(q,))
p2 = multiprocessing.Process(target=work2, args=(q,))
p1.start()
p2.start()
if __name__ == '__main__':
main()
7、进程池pool
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务,请看下面的实例:
代码1:
import multiprocessing
import os
def work1(i):
print('第 %d 次运行,当前进程是:%d' % (i, os.getpid()))
open('xxx.py').read()
def main():
"""使用进程池并发处理多个任务"""
pool = multiprocessing.Pool(3) # 1. 创建进程池
for i in range(100):
pool.apply_async(work1, (i,)) # 2. 添加任务,任务会立即运行
pool.close() # 关闭进程池,关闭后pool不再接收新的请求
pool.join() # 等待pool中所有子进程执行完成,必须放在close语句之后
if __name__ == '__main__':
main()
multiprocessing.Pool常用函数解析:
- apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
- close():关闭Pool,使其不再接受新的任务;
- terminate():不管任务是否完成,立即终止;
- join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through inheritance.
代码2:
# 修改import中的Queue为Manager
from multiprocessing import Manager,Pool,Queue
import os,time,random
def reader(q):
print("reader启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in range(q.qsize()):
print("reader从Queue获取到消息:%s" % q.get(True))
def writer(q):
print("writer启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in "gaohan":
q.put(i)
if __name__=="__main__":
print("(%s) start" % os.getpid())
q = Manager().Queue() # 使用Manager中的Queue
# q = Queue()
po = Pool()
po.apply_async(writer, (q,))
time.sleep(1) # 先让上面的任务向Queue存入数据,然后再让下面的任务开始从中取数据
po.apply_async(reader, (q,))
po.close()
po.join()
print("(%s) End" % os.getpid())
结果:
(31031) start
writer启动(31037),父进程为(31031)
reader启动(31037),父进程为(31031)
reader从Queue获取到消息:g
reader从Queue获取到消息:a
reader从Queue获取到消息:o
reader从Queue获取到消息:h
reader从Queue获取到消息:a
reader从Queue获取到消息:n
(31031) End