进程2
文章目录
1、代码创建进程
创建进程的本质:在内存中申请一块内存空间用于运行相应的程序代码
创建进程的方式
鼠标双击桌面一个应用启动一个应用 就是会启动和创建一些进程
代码创建
在不同的操作系统创建进程的要求不一样
在windows中创建进程是以倒模块的方式进行 所以创建进程的代码必须写在__main__
子代码中
否则会直接报错 因为在无限制创建进程 (进入死循环)
在linux和mac中创建进程是直接拷贝一份源代码然后执行 不要写在__main__
子代码中
# 第一种创建进程的方式
import time
from multiprocessing import Process
#创建一个函数
def task(name):
print('%s is running' % name)
time.sleep(3)
print('%s is over' % name)
if __name__ == '__main__':
# 创建一个进程对象
p = Process(target=task, args=('kk',))
# 告诉操作系统创建一个新的进程
p.start()
print('主进程')
#第二种创建进程的方式
from multiprocessing import Process
import time
# 创建一个类继承 Process父类 来使用其中的方法
class Myprocess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name}正在运行')
time.sleep(3)
print(f'{self.name}运行结束')
if __name__ == '__main__':
# 创建一个进程对象
obj = Myprocess('kk')
# 告诉操作系统船舰了一个进程
obj.start()
print('主进程')
2、join方法
join:主进程等待子进程运行结束之后再运行
推导:
- 直接再主进程代码中添加 time.sleep() 让主进程延时 至子进程运行结束
不合理 因为无法准确的把握子进程的执行时间- 利用join方法
import time
from multiprocessing import Process
def task(name, n):
print(f'{name}正在运行')
time.sleep(n)
print(f'{name}运行结束')
if __name__ == '__main__':
# 创建一个进程对象
p1 = Process(target=task, args=('kk', 3))
p2 =Process(target=task,args=('jj',2))
t1=time.time()
#创建一个进程
p1.start()
#这里 通过join方法 将两个子进程一个个运行
p1.join()
p2.start()
#等子进程运行完 在再继续执行主进程
p2.join()
end_time=time.time()-t1
print(f'程序运行时间 {end_time}')
print('主进程')
3、进程间数据默认隔离
多个进程数据彼此之间默认是相互隔离的
如果想要交互 需要借助于 管道 队列
#父进程 与子进程 完全是两个空间 可以看成是平行世界 子进程不管怎么改 都不影响 父进程这边的代码
from multiprocessing import Process
money = 100
def task():
global money
money =666
print(f'子进程有{money}$')
if __name__ == '__main__':
p1 =Process(target=task)
p1.start()
p1.join()
print(f'父进程有{money}$')
4、进程间通信(IPC机制)
Queue类容器 实现先进先出
队列与栈回顾
队列:先进先出(类似于排队)
栈:先进后出(类似于子弹装进弹夹)
put 方法 尾部添加数据
get方法 从队列取头部取数据 没取到 会进入阻塞态
from multiprocessing import Queue
# 先创建队列列表
q = Queue(3) # 括号内参数 为可容纳的数据个数 默认为:2147483647
# 往队列添加数据
q.put(111)
#判断队列是哦福已经存满
print(q.full())
q.put(222)
q.put(333)
print(q.full())
#超出数据存放极限 那么程序一直处于阻塞态 直到队列中有数据被取出
# q.put(444)
#从队列中获取数据
print(q.get()) # 如果取不到会进入阻塞态
q.put(444)
print(q.get())
print(q.get_nowait()) #如果 被取完了 会直接报错
# print(q.get_nowait()) #如果队列中 之后没有数据可取 俺么会直接报错
# 判断队列是哦福已经空了
print(q.empty())
q.full() 判断队列内是否存满 可能刚判断完里面数据就被改动了 下面同理
q.empty()
q.get_nowait()
上述方法在多进程下不能准确使用
4.1、IPC机制
主进程与子进程通信
子进程与子进程通信
from multiprocessing import Queue,Process
def procedure(q):
q.put('子进程procedure往队列中添加的数据')
def consumer(q):
print('子进程的consumer 从队列中获取数据',q.get())
if __name__ == '__main__':
# 在主进程中 产生q对象 确保所有的子进程使用的是相同的q
q = Queue()
p1 = Process(target=procedure,args=(q,))
p2 = Process(target=consumer,args=(q,))
p1.start()
p2.start()
print('主进程')
# print('主进程 从队列中获取数据',q.get())
# 通过将 q对象创建在 主程序中, 那么子程序在产生时都会 经过q对象
5、生产者消费者模型
生产者
产生数据
消费者
处理数据
回忆过去 爬取红牛分公司
- 生产者:获取的网页数据的代码(函数)
- 爬
- 消费者:从网页数据中筛选出符合条件的数据(函数)
- 筛选
完整的生产者 消费者模型至少有三个部分
生产者
消息队列
消费者
6、进程相关方法
查看进程号
#通过 current_process:
from multiprocessing import current_process
print(current_process().pid) #查看当前进程号
#通过os 模块
import os
print(os.getpid()) #查看当前进程号
print(os.getppid()) #查看它的父进程 进程号 即主进程号
销毁子进程
p1.terminate()
判断 进程是否存货
# 我们都是跟操作系统打交道 都是异步的 所以 代码运行速度很快 操作系统没有反应那么快
p1.is_alive
7、守护进程
如何理解守护进程
伴随着守护对象的存活而存活 死亡而死亡
from multiprocessing import Process
import time
def task(name):
print('大内总管:%s存货'% name)
time.sleep(3)
print('大内总管 %s 挂了'% name)
if __name__ == '__main__':
p = Process(target=task ,args=('kk',))
# 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
p.daemon = True
p.start()
print('主进程')
8、僵尸进程与孤儿进程
僵尸进程
进程已经运行结束了 但是相关的资源并没有完全清空
需要父进程参与回收
孤儿进程
父进程意外死亡 子进程正常运行 该子进程就称之为孤儿进程
孤儿进程 也不是没有人管 操作系统 会自动分配福利院接收
9、互斥锁
模拟抢票
查票
买票
from multiprocessing import Process
import time
import json
import random
# 查票
def search(name):
with open(r'data.json', 'r', encoding='utf')as data_r:
data = json.load(data_r)
print(f'{name}正在查票 当前余票{data.get("ticket_num")}')
# 买票
def buy(name):
# 再次确认票
with open(r'data.json', 'r', encoding='utf')as data_r:
data = json.load(data_r)
# 模拟网络延迟
time.sleep(random.randint(1, 3))
if data.get('ticket_num') > 0:
data['ticket_num'] -= 1
with open(r'data.json', 'w', encoding='utf')as data_w:
json.dump(data, data_w)
print('%s 买票成功' % name)
else:
print('%s 很倒霉 没有轮到票' % name)
def run(name):
search(name)
buy(name)
if __name__ == '__main__':
for i in range(20):
p = Process(target=run,args=('用户%s'%i,))
p.start()
作业
import socket
import struct
from multiprocessing import Process,Queue
def ser(name,sock):
while True:
try:
print(f'客服{name}为您服务')
# 接收客户端发送的数据长度的报头
res = sock.recv(4)
# 获取真实长度
res_c = struct.unpack('i', res)[0]
# 接收真实数据
data_c = sock.recv(res_c)
data = str(data_c, 'utf')
print(data)
# 将接收到的数据转大写
data_s = data.upper()
data_s = bytes(data_s, 'utf')
# 获取数据bytes长度
res_s = len(data_s)
res = struct.pack('i', res_s)
# 发送报头数据
sock.send(res)
sock.send(data_s)
except Exception:
print(f'客服{name}结束')
break
if __name__ == '__main__':
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(3)
# sock, address = server.accept()
for i in range(5):
# 就绪阶段
sock, address = server.accept()
p = Process(target=ser,args=(f'{i}',sock))
p.start()
#客户端
import socket
import struct
#创建 对象
client=socket.socket()
client.connect(('127.0.0.1',8080))
while True:
s_data= input('请输入字母>>>').strip()
if not (s_data.isalpha() and len(s_data)!=0):
print('输入不规范')
break
#将数据 编码
s_data=bytes(s_data,'utf')
res= len(s_data)
res_c=struct.pack('i',res)
client.send(res_c)
client.send(s_data)
# 获取真实数据长度打包后的数据
res = client.recv(4)
# 数据解包获取真实的数据长度
res_r = struct.unpack('i', res)[0]
# 通过真实数据长度 获取真实数
data = client.recv(res_r)
# 打印
# 解码
data = str(data, 'utf')
print(data)