进程 join方法 Queue 守护进程 互斥锁

进程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:主进程等待子进程运行结束之后再运行

推导:

  1. 直接再主进程代码中添加 time.sleep() 让主进程延时 至子进程运行结束
    不合理 因为无法准确的把握子进程的执行时间
  2. 利用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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值