一 Process对象的join方法
在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况
情况一:在主进程的任务与子进程的任务彼此独立的情况下,主进程的任务先执行完毕后,主进程还需要等待子进程执行完毕,然后统一回收资源。
情况二:如果主进程的任务在执行到某一个阶段时,需要等待子进程执行完毕后才能继续执行,就需要有一种机制能够让主进程检测子进程是否运行完毕,在子进程执行完毕后才继续执行,否则一直在原地阻塞,这就是join方法的作用
# join方法
from multiprocessing import Process
import time
import os
def task(name): # os.getppid()查看父进程编号
print("%s is running, parent id is <%s>" % (os.getpid(), os.getppid())) # os.getpid()查看自己进程编号
time.sleep(3) # 模拟任务运行一段时间
print("%s is done, parent id is <%s>" % (os.getpid(), os.getppid()))
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
# Process(target=task, kargs={"name" : "子进程"}) # 方式1
p = Process(target=task, args=("子进程1",)) # 方式2 实例化得到一个对象
p.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task
p.join() # 主进程会等子进程运行(主进程基于子进程执行的结果进行后续代码的执行)
print("主", os.getpid(), os.getppid()) # 此时的父进程是pycharm
print(p.pid) # p对象下的pid(验证僵尸进程)
10952 is running, parent id is <8624>
10952 is done, parent id is <8624>
主 8624 124
10952
from multiprocessing import Process
import time
import os
def task(name, n): # os.getppid()查看父进程编号
print("%s is running" % name) # os.getpid()查看自己进程编号
time.sleep(n) # 模拟任务运行一段时间
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
start = time.time()
p1 = Process(target=task, args=("子进程1", 5))
p2 = Process(target=task, args=("子进程2", 3))
p3 = Process(target=task, args=("子进程3", 2))
p_l = [p1, p2, p3]
# p1.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task(不一定按顺序)
# p2.start()
# p3.start()
for i in p_l: # 简写
i.start()
# p1.join() # 让主进程等,连续三个并发执行
# p2.join()
# p3.join()
for p in p_l:
p.join()
print("主", (time.time()-start)) # 此时的父进程是pycharm
子进程1 is running
子进程2 is running
子进程3 is running
主 5.103978633880615
注意:
进程只要start就会在开始运行了,所以p1-p3.start()时,系统中已经有并发的进程了
join是让主线程等,而p1-p3仍然是并发执行的,p1.join的时候,其余p2,p3,p4仍然在运行,等#p1.join结束,可能p2,p3早已经结束了,这样p2.join,p3.join直接通过检测,无需等待
所以3个join花费的总时间仍然是耗费时间最长的那个进程运行的时间
串行
# 串联执行
from multiprocessing import Process
import time
import os
def task(name, n): # os.getppid()查看父进程编号
print("%s is running" % name) # os.getpid()查看自己进程编号
time.sleep(n) # 模拟任务运行一段时间
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
start = time.time()
p1 = Process(target=task, args=("子进程1", 5))
p2 = Process(target=task, args=("子进程2", 3))
p3 = Process(target=task, args=("子进程3", 2))
p1.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task(不一定按顺序)
p1.join() # 主程序再等P1
p2.start() # p2 才开始
p2.join()
p3.start()
p3.join()
print("主", (time.time()-start)) # 此时的父进程是pycharm
子进程1 is running
子进程2 is running
子进程3 is running
主 10.3139066696167
二 Process对象的其他属性或方法
进程对象的其他方法一:is_alive
# 了解 p.is_alive()
from multiprocessing import Process
import time
import os
def task(name): # os.getppid()查看父进程编号
print("%s is running, parent id is <%s>" % (os.getpid(), os.getppid())) # os.getpid()查看自己进程编号
time.sleep(3) # 模拟任务运行一段时间
print("%s is done, parent id is <%s>" % (os.getpid(), os.getppid()))
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
# Process(target=task, kargs={"name" : "子进程"}) # 方式1
p = Process(target=task, args=("子进程1",)) # 方式2 实例化得到一个对象
p.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task
print(p.is_alive()) # 判断活着还是死的
p.join() # 主进程会等子进程运行(主进程基于子进程执行的结果进行后续代码的执行)
print("主", os.getpid(), os.getppid()) # 此时的父进程是pycharm
print(p.pid) # p对象下的pid(验证僵尸进程)
print(p.is_alive()) # 判断活着还是死的
进程对象的其他属性:terminal
# 了解 p.terminate()
from multiprocessing import Process
import time
import os
def task(name): # os.getppid()查看父进程编号
print("%s is running, parent id is <%s>" % (os.getpid(), os.getppid())) # os.getpid()查看自己进程编号
time.sleep(3) # 模拟任务运行一段时间
print("%s is done, parent id is <%s>" % (os.getpid(), os.getppid()))
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
# Process(target=task, kargs={"name" : "子进程"}) # 方式1
p = Process(target=task, args=("子进程1",)) # 方式2 实例化得到一个对象
p.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task
print("主")
p.terminate() # 给操作系统发出信号终止进程
time.sleep(3)
print(p.is_alive())
进程对象的其他属性:name
# 了解 p.name
from multiprocessing import Process
import time
import os
def task(name): # os.getppid()查看父进程编号
print("%s is running, parent id is <%s>" % (os.getpid(), os.getppid())) # os.getpid()查看自己进程编号
time.sleep(3) # 模拟任务运行一段时间
print("%s is done, parent id is <%s>" % (os.getpid(), os.getppid()))
if __name__ == "__main__": # windows 一定要把开启指令放到main下面 Linux无所谓
# Process(target=task, kargs={"name" : "子进程"}) # 方式1
p = Process(target=task, args=("子进程1",), name="我的进程") # 方式2 实例化得到一个对象
p.start() # (仅仅只是给操作系统发送了一个信号)开启子进程,帮你执行task
print("主")
print(p.name) # 查看进程名称(默认为Process-1)
三 练习题
1、改写下列程序,分别别实现下述打印效果
from multiprocessing import Process
import time
import random
def task(n):
time.sleep(random.randint(1,3))
print('-------->%s' %n)
if __name__ == '__main__':
p1=Process(target=task,args=(1,))
p2=Process(target=task,args=(2,))
p3=Process(target=task,args=(3,))
p1.start()
p2.start()
p3.start()
print('-------->4')
效果一:保证最先输出-------->4
-------->4
-------->1
-------->3
-------->2
from multiprocessing import Process
import time
import random
def task(n):
time.sleep(random.randint(1, 3))
print('-------->%s' % n)
if __name__ == '__main__':
p1 = Process(target=task, args=(1,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(3,))
p_1 = [p1, p2, p3]
for p in p_1:
p.start()
print('-------->4')
效果二:保证最后输出-------->4
-------->2
-------->3
-------->1
-------->4
from multiprocessing import Process
import time
import random
def task(n):
time.sleep(random.randint(1, 3))
print('-------->%s' % n)
if __name__ == '__main__':
p1 = Process(target=task, args=(1,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(3,))
p_1 = [p1, p2, p3]
for p in p_1:
p.start()
for p in p_1:
p.join()
print('-------->4')
效果三:保证按顺序输出
-------->1
-------->2
-------->3
-------->4
from multiprocessing import Process
import time
import random
def task(n):
time.sleep(random.randint(1, 3))
print('-------->%s' % n)
if __name__ == '__main__':
p1 = Process(target=task, args=(1,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(3,))
p_1 = [p1, p2, p3]
for p in p_1:
p.start()
p.join()
print('-------->4')
2、判断上述三种效果,哪种属于并发,哪种属于串行?
answer
效果一与效果二,是并发,效果三是串行