多进程-join()方法和其他方法
一、join()方法
from multiprocessing import Process
import time
import os
def task(name):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(3)
print("%s is done, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
if __name__ == '__main__':
p = Process(target=task, args=("子进程1",))
p.start()
p.join() # 等待子进程执行完成之后再执行之后的程序
print("主进程,pid is:%s, 主进程的ppid is:%s" % (os.getpid(), os.getppid()))
运行输出:
子进程1 is running, pid is:13620, ppid is:4336 子进程1 is done, pid is:13620, ppid is:4336 主进程,pid is:4336, 主进程的ppid is:15936
子进程结束后,子进程的pid没有立即回收,主进程结束后才都回收掉。
来进一步看join:
from multiprocessing import Process
import os
def task(name):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
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()
p1.join()
p2.join()
p3.join()
print("主进程,pid is:%s, 主进程的ppid is:%s" % (os.getpid(), os.getppid()))
运行输出:
子进程2 is running, pid is:16784, ppid is:4584 子进程1 is running, pid is:10648, ppid is:4584 子进程3 is running, pid is:9376, ppid is:4584 主进程,pid is:4584, 主进程的ppid is:15936
解释:
我们可以看到我启动了3个子进程,他们的运行顺序是不一样的,为什么这样呢,因为p1.start(), p2.start(), p3.start()虽然你看起来是同时启动的,但是实际上是发送信号给操作系统,而运行的顺序取决于操作系统,后面3个进程都加了join表示都要等待3个进程运行结束后再执行之后的程序,有人说 那这不就变成串行了吗,其实不是的,因为举个例子,加入p1运行需要2秒钟,p2运行需要5秒钟,p3运行需要3秒钟,如上面例子所示,程序实际运行时间为5秒,因为3个进程都同时向操作系统发送信号需要执行,然后3个进程都执行的join等待子进程运行结束,当还在等待p2执行完成的时候,p1和p3也在执行,等p2执行完,p1和p3早就已经执行完了,所以整个过程只需要5秒,看下面的例子吧:
from multiprocessing import Process
import time
import os
def task(name, n):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(n)
if __name__ == '__main__':
start = time.time()
p1 = Process(target=task, args=("子进程1", 2))
p2 = Process(target=task, args=("子进程2", 5))
p3 = Process(target=task, args=("子进程3", 3))
# p1.start()
# p2.start()
# p3.start()
# p1.join()
# p2.join()
# p3.join()
# 简写为for循环
p_list = [p1, p2, p3]
for p in p_list: # 写为for循环
p.start()
for p in p_list: # 写为for循环
p.join()
print("主进程,pid is:%s, total runtime:%s" % (os.getpid(), time.time() - start))
运行输出:
子进程1 is running, pid is:10088, ppid is:5540 子进程2 is running, pid is:8504, ppid is:5540 子进程3 is running, pid is:19464, ppid is:5540 主进程,pid is:5540, total runtime:6.240571737289429
运行的最后时间为6.2秒。不是我们所说的5秒,但是相差不大,因为操作系调度原因,但是可以说明3个进程是并发运行的,而不是串行。
如果一定要实现串行也是可以的,换一种写法就可以:
from multiprocessing import Process
import time
import os
def task(name, n):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(n)
if __name__ == '__main__':
start = time.time()
p1 = Process(target=task, args=("子进程1", 2))
p2 = Process(target=task, args=("子进程2", 5))
p3 = Process(target=task, args=("子进程3", 3))
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
print("主进程,pid is:%s, total runtime:%s" % (os.getpid(), time.time() - start))
运行结果:
子进程1 is running, pid is:11856, ppid is:11708 子进程2 is running, pid is:19248, ppid is:11708 子进程3 is running, pid is:14572, ppid is:11708 主进程,pid is:11708, total runtime:14.602144479751587
总共耗时14秒。每一个子进程开启的时候,随即就在等待这个子进程的运行结束,然后再开启下一个子进程,所以每一个子进程都会等待他上一个子进程的结束,那么总的运行时间就累加起来了,运行的时候就是一个个运行的,也就是串行了。
二、其他方法
p1.is_alive() , p1.pid , p1.name
p1.is_alive() 查看 子进程的存活状态
p1.pid 查看子进程的pid,和os.getpid() 一样
p1.name 查看子进程的名字,由name参数决定,默认为 Process-1
来看下面的例子:
from multiprocessing import Process
import time
import os
def task(name, n):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(n)
if __name__ == '__main__':
start = time.time()
p1 = Process(target=task, name="subprocess-1", args=("子进程1", 2))
p1.start()
print("进程是否存活:", p1.is_alive())
p1.join()
print("进程是否存活", p1.is_alive())
print("进程的PID:", p1.pid)
print("进程的名字:", p1.name)
print("主进程,pid is:%s, total runtime:%s" % (os.getpid(), time.time() - start))
运行输出:
进程是否存活: True 子进程1 is running, pid is:6844, ppid is:15124 进程是否存活 False 进程的PID: 6844 进程的名字: subprocess-1 主进程,pid is:15124, total runtime:3.1747219562530518
p1.terminate()
p1.terminate() 发送终止信号给操作系统。
from multiprocessing import Process
import time
import os
def task(name, n):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(n)
if __name__ == '__main__':
start = time.time()
p1 = Process(target=task, name="subprocess-1", args=("子进程1", 2))
p1.start()
p1.terminate()
print("进程是否存活:", p1.is_alive())
print("主进程,pid is:%s, total runtime:%s" % (os.getpid(), time.time() - start))
运行输出:
进程是否存活: True 主进程,pid is:17276, total runtime:0.021531343460083008
可以看到,为什么执行了p1.terminate()进程还是返回True存活的呢,因为p1.start() 和 p1.terminate()都是给操作系统发送信号,发送了启动信号后,随即就发送terminate信号,系统还来不及处理,所以马上查看进程是存活的,如果此时在terminate之后加一个sleep(2)或者join 等一下,则就会返回False了,如下:
from multiprocessing import Process
import time
import os
def task(name, n):
print("%s is running, pid is:%s, ppid is:%s" % (name, os.getpid(), os.getppid()))
time.sleep(n)
if __name__ == '__main__':
start = time.time()
p1 = Process(target=task, name="subprocess-1", args=("子进程1", 2))
p1.start()
p1.terminate()
time.sleep(2)
print("进程是否存活:", p1.is_alive())
print("主进程,pid is:%s, total runtime:%s" % (os.getpid(), time.time() - start))
运行输出:
进程是否存活: False 主进程,pid is:14264, total runtime:2.0259580612182617
三、练习题:
1. 证明进程内存空间是隔离的。
from multiprocessing import Process
n = 100
def work():
global n
n = 0
print("子进程,n=", n)
if __name__ == '__main__':
p = Process(target=work)
p.start()
p.join()
print("主进程,n=", n)
运行输出:
子进程,n= 0 主进程,n= 100
2. 基于多进程实现并发的套接字通信?
服务端:
import socket
from multiprocessing import Process
def talk(conn):
while True:
data = conn.recv(1024)
conn.send(data.upper())
conn.close()
def server(ip, port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((ip, port))
server.listen(5)
while True:
print("等待连接...")
conn, client_addr = server.accept()
print("客户端已连接:", client_addr)
p = Process(target=talk, args=(conn,))
p.start()
print("子进程已启动,pid为: %s, 进程名为:%s" % (p.pid, p.name))
server.close()
if __name__ == '__main__':
server("127.0.0.1", 9999)
客户端:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 9999))
while True:
msg = input(">>: ").strip()
if not msg: continue
client.send(msg.encode("utf-8"))
data = client.recv(1024)
print(data.decode("utf-8"))
连接2个客户端后服务端打印的信息如下:
等待连接... 客户端已连接: ('127.0.0.1', 22035) 子进程已启动,pid为: 6436, 进程名为:Process-1 等待连接... 客户端已连接: ('127.0.0.1', 22051) 子进程已启动,pid为: 11776, 进程名为:Process-2 等待连接...
每个客户端都能够正常执行。
共有 0 条评论