并发-2

并发编程

目录

  • 创建进程的多种方式
  • join方法
  • 进程间数据默认隔离
  • 进程间通信(IPC机制)
  • 生产者消费者模型
  • 进程的相关方法
  • 守护进程
  • 僵尸进程和孤儿进程

创建进程的多种方式

  • 创建进程的方法

    1. 双击点击桌面程序图标
    2. 用代码创建进程
  • 如何用代码创建进程

    1. 用process方法创建

      from multiprocessing import Process
      import time
      
      
      def task(name):
          print(f'{name}正在运行')
          time.sleep(3)
          print(f'{name}运行结束')
      
      if __name__ == '__main__':
          p = Process(target=task, args=('jason',))  # 创建一个进程对象
          p.start()  # 告诉操作系统创建一个进程(异步操作)
          # task('jason')  # 普通的函数调用是同步操作
          print('主进程')
      

      创建进程的代码在不同的操作系统中 底层原理有区别!!!
      在windows中 创建进程类似于导入模块
      if __ name__ == '__ main__': 启动脚本
      在mac、linux中 创建进程类似于直接拷贝
      不需要启动脚本 但是为了兼容性 也可以使用

    2. 用类来创建

      class MyProcess(Process):
          def __init__(self, name):
              super().__init__()
              self.name = name
      
          def run(self):
              print(f'{self.name}正在运行')
              time.sleep(5)
              print(f'{self.name}运行结束')
      
      
      if __name__ == '__main__':
          obj = MyProcess('jason')
          obj.start()
          print('主进程')
      

join方法

主程序等待子程序运行结束之后再运行

def task(name, n):
    print(f'{name}正在运行')
    time.sleep(n)
    print(f'{name}运行结束')


if __name__ == '__main__':
    p1 = Process(target=task, args=('jason', 1))  # args就是通过元组的形式给函数传参
    p2 = Process(target=task, args=('kevin', 2))  # 也可以通过kwargs={'name':'jason', 'n':1} 麻烦
    p3 = Process(target=task, args=('jerry', 3))
    start_time = time.time()
    
    
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
     end_time = time.time() - start_time
    print('总耗时:%s' % end_time)
 """ 总耗时为6.n s 原因: 类似于单进程 先运行完一个再运行下一个"""
    
    
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('总耗时:%s' % end_time)
    print('主进程')
'''
并发进行,几乎同时进行
一定要看准join的执行位置 以及多任务情况下等待的目标
'''

进程间数据默认隔离

​ 多个进程之间的数据是默认相互隔离的

​ 如果真的想交互 需要借助于'管道'或者'队列'

from multiprocessing import Process

money = 100


def task():
    global money
    money = 666
    print('子进程打印的money', money)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('父进程打印的money', money)

进程间通信(IPC机制)—— 队列

  • 什么是队列

    ​ 队列(先进先出)

    ​ 创建共享的进程队列,Queue是多进程安全的队列,用Queue方法实现多进程之间的数据传输

  • 如何进行通信

    from multiprocessing import Queue
        # 1.创建队列对象
        q = Queue(3)  # 括号内指定队列可以容纳的数据个数 默认:2147483647
        # 2.往队列添加数据
        # q.put(111)
        # print(q.full())  # 判断队列是否已经存满
        # q.put(222)
        # q.put(333)
        # print(q.full())
        # q.put(444)  # 超出数据存放极限 那么程序一致处于阻塞态 直到队列中有数据被取出
        # 3.从队列中取数据
        print(q.get_nowait())
        print(q.get_nowait())
        print(q.get_nowait())  # 队列中如果没有数据可取 直接报错
        # print(q.get())
        # print(q.empty())  # 判断队列是否已经空了
        # print(q.get())
        # print(q.get())
        # print(q.empty())
        # print(q.get())  # 超出数据获取极限 那么程序一致处于阻塞态 直到队列中有数据被添加
    

    方法 作用 不足
    full() 判断队列是否已经存满 多进程下不能准确使用
    empty() 判断队列是否已经空了 多进程下不能准确使用
    get_nowait() 队列中如果没有数据可取 直接报错 多进程下不能准确使用
    get() 取出队列中的数据 超出数据获取极限 那么程序一致处于阻塞态
    直到队列中有数据被添加
    put() 往队列添加数据 超出数据存放极限 那么程序一致处于阻塞态
    直到队列中有数据被取出

    ​ full()、empty()、get_nowait() 这些方法在单进程下可以实现,但在多进程下,由于这个队列是通用的,在同一时间一个进程存取,另一个进程进行取存,无法得到及时更新队列,所以并不能准确使用

  • IPC机制

    1. 主进程与子进程通信
    2. 子进程与子进程通信
    from multiprocessing import Queue, Process
    
    
    def procedure(q):
        q.put('子进程procedure往队里中添加了数据')
    
    
    def consumer(q):
        print('子进程的consumer从队列中获取数据', q.get())
    
    
    if __name__ == '__main__':
        q = Queue()  # 在主进程中产生q对象 确保所有的子进程使用的是相同的q
        p1 = Process(target=procedure, args=(q,))
        p2 = Process(target=consumer, args=(q,))
        p1.start()
        p2.start()
        print('主进程')
    
  • 生产者消费者模型

    分类 作用 举例
    生产者 产生数据 获取网页数据的代码
    消费队列/数据库 将产生的数据经行存储 将获取到的网页的数据存储到文本文件或数据库
    消费者 处理存储的数据 从获取的网页数据中筛选出符合条件的数据

进程的相关方法

执行操作 方法
查看进程号 current_process().pid
os.getpid()/os.getppid()
销毁子进程 terminate()
判断进程是否存活 is_alive()
  • 查看进程号

    	from multiprocessing import current_process
    	import os
    	current_process().pid
    	os.getpid()
    	os.getppid()
    
  • 守护进程

    • 什么是守护进程

      ​ 伴随着守护对象的存活而存活 死亡而死亡

    • 具体体现

      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=('基佬',))
          # p.daemon = True  # 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
          p.start()
          p.daemon = True  # 必须在start之前执行
          print('天子Jason寿终正寝!!!')
      
  • 僵尸进程与孤儿进程

    • 僵尸进程

      ​ 进程已经运行结束 但是相关的资源并没有完全清空

      ​ 需要父进程参与回收

    • 孤儿进程

      ​ 父进程意外死亡 子进程正常运行 该子进程就称之为孤儿进程

      ​ 孤儿进程也不是没有人管 操作系统会自动分配福利院接收

posted @ 2022-08-09 16:04  Nirvana*  阅读(29)  评论(0)    收藏  举报