进程
- 进程又称重量级进程,正在执行中的程序称为进程。进程的执行会占用内存等资源。多个进程同时执行时,每个进程的执行都需要由操作系统按一定的算法(RR调度、优先数调度算法等)分配内存空间。
- 并行与并发
-
并行:在多核系统中,每个cpu执行一个进程,可以理解为cpu的数大于进程数,所有进程同时进行。
-
并发:在操作系统中同时执行多个进程,可以理解为cpu的数小于进程数,有些进程会没有机会执行。
-
并发与并行的区别:并行指两个或多个程序在同一时刻执行;并发指两个或多个程序在同一时间间隔内发生,可以理解为在表面上看是同时进行,但在同一时刻只有少于程序的总数的程序在执行,计算机利用自己的调度算法让这些程序分时的交叉执行,由于交换的时间非常短暂,宏观上就像是在同时进行一样。
-
1、进程简单实现
import multiprocessing
def demo_one():
for i in range(3):
print('子进程one- start --{}'.format(multiprocessing.current_process().name))
def demo_two():
for i in range(3):
print('子进程two- start --{}'.format(multiprocessing.current_process().name))
if __name__ == '__main__':
print('主进程- start --{}'.format(multiprocessing.current_process().name))
# 创建进程对象
# target 传入调用函数
p1 = multiprocessing.Process(target=demo_one)
p2 = multiprocessing.Process(target=demo_two)
p1.start()
p2.start()
print('主进程- end --{}'.format(multiprocessing.current_process().name))
- 运行结果
主进程- start --MainProcess
主进程- end --MainProcess
子进程two- start --Process-2
子进程two- start --Process-2
子进程two- start --Process-2
子进程one- start --Process-1
子进程one- start --Process-1
子进程one- start --Process-1
2、进程间信息传递
- 进程间不同享全局变量,进程间需要信息传递时,采用队列
- 可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序
import multiprocessing
import time
from multiprocessing import Queue
def demo_one(q):
for i in range(3):
time.sleep(1)
try:
num = q.get()
print(num)
except:
pass
finally:
print('子进程one- start --{}'.format(multiprocessing.current_process().name))
def demo_two(q):
for i in range(3):
q.put(6)
time.sleep(0.5)
print('子进程two- start --{}'.format(multiprocessing.current_process().name))
if __name__ == '__main__':
q = Queue(3) # Queue()若不知道队列内存储信息数量,默认是无限大,直到内存存满
# 创建进程对象
print('主进程- start --{}'.format(multiprocessing.current_process().name))
# 进程间不共享全局变量,因此需要将初始化的`q`对象,传递到每一个子进程中
p1 = multiprocessing.Process(target=demo_one, args=(q,))
p2 = multiprocessing.Process(target=demo_two, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
print('主进程- end --{}'.format(multiprocessing.current_process().name))
- 执行结果
主进程- start --MainProcess
子进程two- start --Process-2
6
子进程one- start --Process-1
子进程two- start --Process-2
子进程two- start --Process-2
6
子进程one- start --Process-1
6
子进程one- start --Process-1
主进程- end --MainProcess
3、进程池Pool
-
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
-
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务,请看下面的实例:
# 修改import中的Queue为Manager
from multiprocessing import Manager,Pool
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 "python":
q.put(i)
if __name__=="__main__":
print("(%s) start" % os.getpid())
q = Manager().Queue() # 使用Manager中的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())
- 执行结果
(20052) start
writer启动(19584),父进程为(20052)
reader启动(11396),父进程为(20052)
reader从Queue获取到消息:p
reader从Queue获取到消息:y
reader从Queue获取到消息:t
reader从Queue获取到消息:h
reader从Queue获取到消息:o
reader从Queue获取到消息:n
(20052) End
multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;