多进程
# join() # 阻塞等待子进程的结束 import time from multiprocessing import Process # =========运行完了和10个*是会先被打印的,20个*后面再打印 # def func(arg1, arg2): # print('*' * arg1) # time.sleep(5) # print('*' * arg2) # # if __name__ == '__main__': # p = Process(target=func, args=(10, 20)) # p.start() # print('===========: 运行完了') # 现在想让20个*打印完了,在执行父进程的===运行完了 # =========运行完了和10个*是会先被打印的,20个*后面再打印 def func(arg1, arg2): print('*' * arg1) time.sleep(5) print('*' * arg2) if __name__ == '__main__': p = Process(target=func, args=(10, 20)) p.start() # 启动子进程 print('hahaha') p.join() # 阻塞等待子进程的结束 print('===========: 运行完了')
2.开启多个进程的方法
# 同时开启多个子进程 import time import os from multiprocessing import Process # 开启多进程的一种方法 # def func(arg1, arg2): # print(os.getpid(), '*' * arg1) # time.sleep(5) # print(os.getpid(), '*' * arg2) # # if __name__ == '__main__': # p1 = Process(target=func, args=(5, 10)) # p2 = Process(target=func, args=(4, 6)) # # p1.start() # p2.start() # # # for i in range(10): # # p = Process(target=func, args=(2 * i, 5 *i)) # # p.start() # # print('haha') # # p1.join() # p2.join() # # print('父进程执行完了') # -------------------------------------------------------- # # 开启多进程的方法也可以用for,但无法使得子进程全部结束后再打印父进程执行完了 # def func(arg1, arg2): # print(os.getpid(), '*' * arg1) # time.sleep(5) # print(os.getpid(), '*' * arg2) # # if __name__ == '__main__': # for i in range(10): # p = Process(target=func, args=(2 * i, 5 *i)) # p.start() # # print('父进程执行完了') # 开启多进程的方法也可以用for,此种方法可使得子进程全部结束后再打印父进程执行完了 def func(arg1, arg2): print(os.getpid(), '*' * arg1) time.sleep(5) print(os.getpid(), '*' * arg2) if __name__ == '__main__': p_lst = [] # 创建了一个list for i in range(10): p = Process(target=func, args=(2 * i, 5 *i)) p_lst.append(p) # 将创建的每个子进程对象加入到list列表中 p.start() [p.join() for p in p_lst] # 遍历列表中的每个子进程对象,都调用join()阻塞等待子进程的结束 print('父进程执行完了')
3.使用自定义类继承Process类,重写run方法和init方法进行启动进程的方法
# 第二种创建多进程的方式 # 创建一个自定义类,继承自Process类 # 必须实现以个run方法,run方法中的代码是在子进程中执行的代码 # 开启子进程的方式是子进程类对象调用start() import os import time from multiprocessing import Process # 创建一个类,继承自Process进程类,并实现一个run方法,run方法中的代码是在子进程中执行的代码 # class MyProcess1(Process): # def run(self): # print(os.getpid()) # print(self.pid) # 查看当前进行的pid # print(self.name) # 查看当前进行的进程名 # # # if __name__ == '__main__': # print('主进程pid %s' % os.getpid()) # p1 = MyProcess1() # p2 = MyProcess1() # # p1.start() # 启动进程类中的继承,运行了run方法 # p2.start() # # p1.join() # p2.join() # # print('父进程执行完了') # 如何传参数呢,下面的方式进行传参,如果需要传参,需要重写一个init方法,并运行将父类init将其属性继承过来,如果不需要传参,则不用重新init函数,只重写run方法即可 class MyProcess1(Process): def __init__(self, arg1, arg2): super().__init__() # 调用父类Process的init方法,因为有很多属性可能在其他我们看不到的地方被使用,所以当我们要重新初始化属性时,要将父类的属性弄过来 self.arg1 = arg1 self.arg2 = arg2 def run(self): print(os.getpid()) print(self.pid) # 查看当前进行的pid print(self.name) # 查看当前进行的进程名 print(self.arg1) print(self.arg2) if __name__ == '__main__': print('主进程pid %s' % os.getpid()) p1 = MyProcess1(2, 5) # 2与5作为参数 p2 = MyProcess1(7, 8) p1.start() # 启动进程类中的继承,运行了run方法 p2.start() p1.join() p2.join() print('父进程执行完了')
4.进程与进程之间数据隔离问题,进程与进程之间数据是隔离的,想要互相交互数据需要通过其他手段(管道,后面再说)
# 进程与进程之间数据是隔离开的 # 父进程与子进程之间数据也是隔离开的 # 进程与进程之间如果不通过特殊的手段(管道),数据是完全隔离的 # 证明父进程与子进程之间的数据也是隔离开的,全局变量无法共用 from multiprocessing import Process import os def func(): global n # 声明使用全局的n n = 0 # 将n赋值为0 实际上是定义了一个n,赋值为0 print('pid : %s' % os.getpid(), n) # 0 if __name__ == '__main__': n = 100 p = Process(target=func) p.start() p.join() print('主进程pid: %s' % os.getpid(), n) # 100
5.使用多进程实现socket服务端的并发,只为了演示多进程,当客户端多时,会存在性能问题。
5.1 server.py
# 使用多进程实现socket服务端的并发 # 下面这种方法,只能同时处理一个客户端 # import socket # # sk = socket.socket() # # sk.bind(('127.0.0.1', 8080)) # # sk.listen() # # while True: # conn, addr = sk.accept() # ret = '你好'.encode('utf-8') # conn.send(ret) # msg = conn.recv(1024).decode('utf-8') # print(msg) # conn.close() # # sk.close() # 下面这种方法,服务端可以实现并发,虽然此种方法可以实现并发,来一个客户端上来就启一个进程与其对应,但此种方法在客户端多时,在性能上会存在问题。socketserver相对于多进程方式实现的并发会好一些 import socket from multiprocessing import Process def serve(conn, addr): ret = '你好'.encode('utf-8') conn.send(ret) msg = conn.recv(1024).decode('utf-8') print(msg) conn.close() if __name__ == '__main__': sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() while True: conn, addr = sk.accept() # 当一个客户端连接上来时,得到客户端连接描述符和客户端ip端口 p = Process(target=serve, args=(conn, addr)) # 就创建一个子进程,将客户端连接符和客户端地址以参数形式传递给子进程 p.start() # 启动子进程
5.2 client.py
import socket sk = socket.socket() sk.connect(('127.0.0.1', 8080)) msg = sk.recv(1024).decode('utf-8') print(msg) inputinfo = input('>>>').encode('utf-8') sk.send(inputinfo) sk.close()
6.关于多进程的补充
from multiprocessing import Process def func(): num = input('>>>') # 不可以,报错 print(num) if __name__ == '__main__': Process(target=func).start() # 进程同步控制 # 锁/信号量/事件 # 进程间通信 # 队列和管道 # 进程间的数据共享 # multiProcess.Manager # 进程池和multiprocessPool