• Day40 进程2


    Day40 进程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('主进程')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    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('主进程')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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}$')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4、进程间通信(IPC机制)

    队列与栈回顾
    队列:先进先出(类似于排队)
    栈:先进后出(类似于子弹装进弹夹)

    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())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    q.full() 判断队列内是否存满 可能刚判断完里面数据就被改动了 下面同理
    q.empty()
    q.get_nowait()
    上述方法在多进程下不能准确使用
    
    • 1
    • 2
    • 3
    • 4

    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对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    5、生产者消费者模型

    生产者
    产生数据

    消费者
    处理数据

    回忆过去 爬取红牛分公司

    • 生产者:获取的网页数据的代码(函数)
    • 消费者:从网页数据中筛选出符合条件的数据(函数)
      • 筛选

    完整的生产者 消费者模型至少有三个部分
    生产者
    消息队列
    消费者

    6、进程相关方法

    查看进程号

    #通过 current_process:
    from multiprocessing import current_process
    print(current_process().pid) #查看当前进程号
    #通过os 模块
    import os
    print(os.getpid())  #查看当前进程号
    print(os.getppid())  #查看它的父进程 进程号 即主进程号
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    销毁子进程

    p1.terminate()
    
    • 1

    判断 进程是否存货

    # 我们都是跟操作系统打交道 都是异步的 所以 代码运行速度很快 操作系统没有反应那么快
    p1.is_alive
    
    • 1
    • 2

    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('主进程')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    作业

    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()
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    #客户端
    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Windows电脑安装Linux(Ubuntu 22.04)系统(图文并茂)
    UltraEdit2024免费版文本编辑器
    Redis常见面试题
    六、不root不magisk不xposed lsposed frida原生修改定位
    开源与闭源:大模型发展的未来之路
    springboot项目:前后端搭建
    负号重载C++
    MATLAB实现AHP层次分析法——以情人节选取礼物为例
    Git实战篇(快速上手精通)
    Linux学习教程(第四章 Linux打包(归档)和压缩)
  • 原文地址:https://blog.csdn.net/weixin_71967396/article/details/126255361