NO.4 Python多进程

NO.4 Python多进程

零蚀


  • 多任务

    • 并发:cpu进行分配时间片,看起来像并行。
    • 并行:多个cpi同时工作,多个程序同时工作。
  • 进程编写

    启动
    调度
    满足条件
    结束
    等待条件
    新建
    就绪
    运行
    等待阻塞
    死亡
    import multiprocessing as mp
    import os
    
    
    def function():
        print("加油")
        print(mp_process.name)
    
    
    if __name__ == '__main__':
        mp_process = mp.Process(target=function)
        mp_process.start()
        print(mp_process.pid)  # 进程id
        print(mp.current_process())  # 当前进程对象
        print("cpu_count:", mp.cpu_count())  # cpu数量
        print("父进程id:", os.getppid())
    
    • 参数的传递
    def function(a, b, c):
        print("加油", a, b, c)
        print(mp_process.name)
    
    
    if __name__ == '__main__':
        # mp_process = mp.Process(target=function, args=(1, 2, 3))
        mp_process = mp.Process(target=function, kwargs={"a": 1, "b": 2, "c": 3})
        mp_process.start()
    
    • 进程的共享

    进程是不能数据通信的,也就是说不可以做到数据共享,案例如下:

    num = 0
    
    
    def a():
        global num
        for i in range(100000):
            num = num + 1
        print("a:", num)
    
    
    def b():
        global num
        for i in range(100000):
            num = num + 1
    
        print("b:", num)
    
    
    if __name__ == '__main__':
        # mp_process = mp.Process(target=function, args=(1, 2, 3))
        mp_process = mp.Process(target=a)
        mp_process.start()
        mp_process1 = mp.Process(target=b)
        mp_process1.start()
    
        time.sleep(3)
        print("main:", num)
    
    

    输出的结果为:

    a: 100000
    b: 100000
    main: 0
    
    • 守护线程
    # 终结当前进程
    mp_process.terminate() 
    # or 
    # 设置守护进程()
    mp_process.daemon=True
    
    

    mp_process.daemon需要在start之前,且执行到时也是干掉子进程,并且干掉了子进程里面的所有缓存资源对象。

    • 消息队列

    进程数据示意图:

    进程1
    进程2
    主进程
    被获取数据num
    被获取数据num
    数据new_num
    数据new_num
    数据num

    添加消息队列

    主进程
    子进程
    进程2
    进程1
    被获取数据num
    被获取数据num
    消息队列num num num num...num
    数据num
    数据new_num
    数据new_num
    • 队列的特性
    queue = multiprocessing.Queue(3)
    
    queue.put(1)
    queue.put("abcd")
    queue.put(["aaa","bbb"])
    
    # 如果队列已满,阻塞程序,直到队列熟取出
    # queue.put(1234)
    
    # 拿到队头,取出队列
    head = queue.get()
    print(head)
    head1 = queue.get()
    print(head1)
    head2 = queue.get()
    print(head2)
    

    如果put 或get过多会导致阻塞,致使其他代码无法继续运行。为了防止阻塞导致崩溃。

    # 添加不了,报异常
    queue.put_nowait("adf")
    # 获取不到,报异常
    queue.get_nowait()
    
    

    设置超时时间,这样也可以起到报错的效果

    head4 = queue.get(timeout=3)
    print(head4)
    

    其他API

    queue.full()  # 判满
    queue.empty()  # 判空(3.7+ ;添加数据需要时间,在添加的过程中还是为空)
    queue.qsize()  # 判size
    
    • 进程间通信
    def put_data(queue):
    for i in range(10):
        print("放数据:", i)
        queue.put(i)
        time.sleep(1)
    
    
    def get_data(queue):
        while True:
            print("取数据:", queue.get(timeout=3))
            time.sleep(1)
    
    
    if __name__ == '__main__':
        queue = mp.Queue()
    
        mp1 = mp.Process(target=put_data, args=(queue,))
        mp2 = mp.Process(target=get_data, args=(queue,))
        mp1.start()
        mp2.start()
    
    • 进程池
    def funcA(str):
        time.sleep(1)
        print("任务A", str)
    
    
    iif __name__ == '__main__':
    
        pool = mp.Pool(3)
        for i in range(10):
            # 指派任务,按照队列任务完成
            pool.apply(funcA, ("fjasfj;" + str(i),))
    
        pool.close()
    

    阻塞当前代码,至当前进程池所有进程执行完毕。

     pool.join()
    

    在进程运行之前或之后运行相应代码。

    result=pool.apply_async(funcA, ("f",))
    # ....
    result.wait()
    
    • 进程池的任务队列

    进程池的队列需要特殊指定的消息队列:

    def write(queue):
    for i in range(10):
        print("写入数据",i)
        queue.put(i)
        time.sleep(1)
    
    
    def read(queue):
        while True:
            print("读取数据",)
            value = queue.get()
            print("读取数据",value)
    
    
    if __name__ == '__main__':
        queue = mp.Manager().Queue(3)
        pool = mp.Pool(2)
    
        pool.apply_async(write, (queue,))
        pool.apply_async(read, (queue,))
        pool.close()
        pool.join()
    

    这里的线程池任务指定,需要指定为异步操作,不然会卡死在某一个apply上,由于队列大小不够。

    其他API

    import os
    
    os.mkdir("path")
    os.makedirs("paths")
    # 遍历dir
    os.listdir("path")
    
    • 进程锁

    比如多个进程写同一个文件

    import multiprocessing
    
    
    # 对文件file进行写入操作
    # "file.txt"
    
    def write_one(file, lock):
        with lock:
            with open(file, "+a") as file1:
                for i in range(10):
                    file1.write("aaa---"+str(i)+ "---")
    
    
    def write_two(file, lock):
        with lock:
            with open(file, "+a") as file2:
                for i in range(10):
                    file2.write("bbb---"+str(i)+"---")
    
    
    if __name__ == '__main__':
        lock = multiprocessing.Lock()
        path = "file.txt"
    
        p1 = multiprocessing.Process(target=write_one, args=(path, lock))
        p2 = multiprocessing.Process(target=write_two, args=(path, lock))
    
        p1.start()
        p2.start()
    
    
    • fork()

    fork主要存在于unix/linux下,也就是mac/linux系统系统,他调用就会产生一个子进程。windows没有fork无法运行,fork会返回两次,一个是当前进程,一个是子进程:

    import os
    import multiprocessing
    
    fork_pid = os.fork()
    
    print("pid:", fork_pid)
    if fork_pid != 0:
        print('我是主进程', multiprocessing.current_process().name)
    else:
            print('我是子进程', multiprocessing.current_process().name)
    

    输出:

    pid: 36396
    我是主进程 34814
    pid: 0
    我是子进程 36395
    
    • PIPE管道

    主要目的还是做进程间通信,PIPE分单双工和全双工,单双工是指通信双方只能有一个发起者和一个接收者,当存在发起者存在的时候,另一方只能由对方完毕之后,才能进行通信。

    半双工

    def sender_process(pipe):
    for i in range(10):
        print("发送方——>pip2", i)
        pipe.send(i)
        time.sleep(1)
    
    
    def receive_process(pipe):
        while True:
            print("接收方——>pip2", pipe.recv())
            time.sleep(1)
    
    
    if __name__ == '__main__':
        # false 单双工, True 全双工
        pipe = mp.Pipe(duplex=False)
    
        p1 = mp.Process(target=receive_process, args=(pipe[0],))
        p2 = mp.Process(target=sender_process, args=(pipe[1],))
    
        p1.start()
        p2.start()
    

    主要的方法是pipe.send(i)pipe.recv()


🔗 前言
🔗 Python 高级列表
🔗 NO.1 Python网络通信
🔗 NO.2 Python Web 服务器
🔗 NO.3 Python多线程&锁
🔗 NO.5 Python协程&生成器
🔗 NO.6 Python正则&爬虫初
🔗 NO.7 Python操作MySQL
🔗 NO.8 Python Spider
🔗 NO.9 Python 装饰器&other

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值