Python进阶-多任务编程-02

Python进阶系列
Python进阶-网络编程-01
Python进阶-网络编程-02
Python进阶-网络编程-03
Python进阶-多任务编程-01
Python进阶-多任务编程-02
Python进阶-多任务编程-03
Python进阶-正则表达式
Python进阶-数据库编程-01
Python进阶-数据库编程-02
Python进阶-数据库编程-03
Python进阶-数据库编程-04
Python进阶-数据拷贝问题
Python进阶-模块导入问题
Python进阶-miniWeb框架

7.1. 进程以及状态

  • 进程:资源分配的基本单位,也是线程的容器
  • 进程的状态
    • 新建
    • 就绪
    • 运行
    • 阻塞
    • 死亡

7.2. 进程-基本使用

  • 进程使用的步骤
  1. 导入模块

      import multiprocessing
    
  2. 创建子进程对象

      process_obj = multiprocessing.Process(target=work1)
    
  3. 启动子进程

    process_obj.start()
    
  • 代码示例:

    import time
    import multiprocessing
    
    
    def work1():
        for i in range(10):
            print("正在运行work1")
            time.sleep(0.5)
    
    if __name__ == '__main__':
        process_obj = multiprocessing.Process(target=work1)
        process_obj.start()
    

7.3. 进程-名称、PID

  • 获取进程的名称

    multiprocessing.current_process()
    
  • 设置进程名称

    multiprocessing.Process(target=xxxx,name="进程名称"
    
  • 获取进程的编号

    # 方法1
    multiprocessing.current_process().pid
    # 方法2
    os.getpid()
    
  • 获取进程的父id

    os.getpid()
    
  • 结束进程

    kill  -9  进程的编号
    
  • 代码示例:

    import time
    import multiprocessing
    import os
    
    def work1():
        for i in range(10):
            # 获取子进程的id
            print("正在运行work1",multiprocessing.current_process().pid)
            # 获取进程的父id
            print("正在运行work1","子进程id:",os.getpid(),"父进程id:",os.getppid())
            time.sleep(2)
    
    if __name__ == '__main__':
        # 获取主进程的名称
        print(multiprocessing.current_process())
    
        # 获取进程编号
        print("主进程编号",os.getpid())
    		
        # 创建进程同时为进程设置名称
        process_obj = multiprocessing.Process(target=work1,name="P1")
        process_obj.start()
    

7.4. 进程-参数传递、全局变量问题

  • 进程的参数传递

    1. args元组

      process_obj = multiprocessing.Process(target=work1,args=(10,100,1000))
      
    2. kwargs字典

      process_obj = multiprocessing.Process(target=work1,kwargs={"c":10,"b":100,"a":1000})
      
    3. 混合args和kwargs

      process_obj = multiprocessing.Process(target=work1,args=(10,),kwargs={"c":10,"b":100})
      
  • 进程间共享全局变量的问题

    • 进程间不能共享全局变量

    • 底层原理:子进程会复制主进程的资源到内部运行

    • 代码示例:

      import multiprocessing
      import time
      
      g_num = 10
      
      def work1():
          global g_num
          for i in range(10):
              g_num+=1
          print("  work1 ",g_num)
      
      def work2():
          print(" work2 ",g_num)
      
      if __name__ == '__main__':
          t1 = multiprocessing.Process(target=work1)
          t2 = multiprocessing.Process(target=work2)
      
          t1.start()
          t2.start()
          time.sleep(3)
          print(g_num)
      

7.5. 进程-守护主进程

  • 进程守护:子进程和主进程的一种约定,当主进程结束的时候,子进程也随之结束

    process_obj.daemon = True
    
  • 结束子进程

    process_obj.terminate()
    
  • 代码示例:

    import time
    import multiprocessing
    
    def work1():
        for i in range(10):
            print("正在运行work1")
            time.sleep(0.5)
    
    if __name__ == '__main__':
        process_obj = multiprocessing.Process(target=work1)
        # 设置进程守护
        process_obj.daemon = True
        process_obj.start()
    
        time.sleep(2)
        print("我要死了")
        exit()
    

7.6. 进程、线程对比

  • 进程与线程的对比
    • 进程是资源分配的基本单元,线程是CPU调度的基本单元
    • 进程运行需要独立的内存资源,线程需要到的是必不可少的一点资源
    • 进程切换慢,线程切换快
    • 线程不能独立运行,必须运行在进程中(提供资源)
    • CPU密集型进程优先,I/O密集型使用线程
    • 程序更稳定进程,线程比较不够稳定
  • 使用
    • 不是非此即彼,而是组合

7.7. 消息队列-基本操作

  • 消息队列:为了实现进程之间的通信

  • 队列的值:可以是数值,字符串,列表,元组,字典

  • 队列的创建

    # 创建含有五个元素的消息队列
    
      multiprocessing.Queue(5)
    
    • 队列的操作

      • 放入值
       # 从队列尾部开始放入值
       queue.put("要放入的数据")
      
      • 取出值
        # 从队列头部开始取出值
        queue.get()
      
    • xxxx_nowait()方式

      • 放入值put_nowait() 特点:队列未满,同put(),但是队列已满,会报错,不等待
      • 取值get_nowait() 特点:队列未空,同get(),但是队列已空,会报错,不等待
  • 代码示例:

    import multiprocessing
    
    queue = multiprocessing.Queue(5)
    
    queue.put(1)
    queue.put("hello")
    queue.put([1,2,3])
    queue.put((4,5,6))
    queue.put({"a":10,"b":4})
    
    for i in range(5):
        value = queue.get()
        print(value)
    

7.8. 消息队列-常见判断

  • 队列空

    queue.empty()
    
  • 队列满

    queue.full()
    
  • 队列元素个数

    queue.qsize()
    
  • 代码示例:

    import multiprocessing
    
    queue = multiprocessing.Queue(3)
    queue.put(1)
    queue.put(2)
    queue.put(3)
    
    # 判断队列是否已满
    isFull = queue.full()
    
    print("isFull",isFull)
    
    value = queue.get()
    print("队列的个数",queue.qsize())
    
    value2 = queue.get()
    value3 = queue.get()
    isEmpty = queue.empty()
    print("isEmpty",isEmpty)
    

7.9. Queue实现进程间通信

  • 思路:利用队列在两个进程间进行传递,进而实现数据共享

    • write_queue(queue)
    • read_queue(queue)
    • 创建一个空队列
    • 把空队列作为参数,先把队列传递给写进程,然后再把队列传递给读进程
    • join() 优先让一个进程先执行完成,另一个进程才能启动
  • 代码示例:

    import time
    import multiprocessing
    
    
    def wtite_queue(queue):
        for i in range(10):
            if queue.full():
                print("队列已满")
                break
            queue.put(i)
            print("写入成功,已经写入:",i)
            time.sleep(0.5)
    
    def read_queue(queue):
        while True:
            if queue.qsize() == 0:
                print("队列已空")
                break
            # 从队列读取数据
            value = queue.get()
            print("已经读取:",value)
    
    
    if __name__ == '__main__':
        queue = multiprocessing.Queue(5)
    
        write_queue_size = multiprocessing.Process(target=wtite_queue,args=(queue,))
        read_queue_size = multiprocessing.Process(target=read_queue,args=(queue,))
    
        write_queue_size.start()
        write_queue_size.join()
        read_queue_size.start()
    

7.10. 进程池Pool

  • 进程池:是一个进程的容器,可以自动创建指定数量的进程,并且管理进程及工作

  • 创建进程池

    multiprocessing.Pool(3)
    
  • 进程池工作方式

    • 同步方式:进程池中的进程,一个执行完毕后,另一个才能执行,多个进程执行有先后顺序

      # pool.apply(函数名,(参数1,参数2,))
      pool.apply(copy_work)
      
    • 异步方式:进程池中的进程,多个进程同时执行,没有先后顺序

      pool.apply_async(函数名,(参数1,参数2))
      pool.apply_async(copy_work)
      
  • 注意:

    • 进程池要close(),表示不再接收新的任务

      pool.close()
      
    • 还要join(),让主线程等待进程池执行结束后再退出

      pool.join()
      
  • 代码示例:

    import time
    import multiprocessing
    
    def copy_work():
        print("正在拷贝文件",multiprocessing.current_process())
        time.sleep(0.5)
    
    if __name__ == '__main__':
        # 创建进程池
        pool = multiprocessing.Pool(3)
    
        for i in range(10):
           # 异步工作方式
           pool.apply_async(copy_work)
    
        # 表示不再接收新的任务
        pool.close()
        # 让主进程等待进程池执行结束后再关闭
        pool.join()
    

7.11. 进程池中的Queue

  • 获取方法

    # 1.创建进程池
    pool = multiprocessing.Pool(2)
    
    # 2.创建进程池中的队列
    queue = multiprocessing.Manager().Queue(5)
    
  • 同步方式

    pool.apply(write_queue,(queue,))
    pool.apply(read_queue,(queue,))
    
  • 异步方式

    result = pool.apply_async(write_queue,(queue,))
    result.wait()
    pool.apply_async(read_queue,(queue,))
    pool.close()
    pool.join()
    
  • 代码示例:

    import time
    import multiprocessing
    
    def write_queue(queue):
        for i in range(10):
            if queue.full():
                print("队列已满")
                break
            queue.put(i)
            print("写入成功,已经写入:",i)
            time.sleep(0.5)
    
    def read_queue(queue):
        while True:
            if queue.qsize() == 0:
                print("队列已空")
                break
            # 从队列读取数据
            value = queue.get()
            print("已经读取:",value)
    
    if __name__ == '__main__':
        # 1.创建进程池
        pool = multiprocessing.Pool(2)
    
        # 2.创建进程池中的队列
        queue = multiprocessing.Manager().Queue(5)
    
        # 异步方式
        result = pool.apply_async(write_queue,(queue,))
        result.wait()
        pool.apply_async(read_queue,(queue,))
        pool.close()
        pool.join()
    

7.12. 案例:文件夹copy器(多进程版)

  • 思路

    1. 定义变量,保存源文件夹、目标文件夹所在的路径
    2. 在目标路径创建新的文件夹
    3. 获取源文件夹中的所有的文件(列表)
    4. 遍历列表,得到所有的文件名
    5. 定义函数,进行文件拷贝
  • 文件拷贝函数

    参数:源文件夹路径 目标文件夹路径 文件名

    1. 拼接源文件和目标文件的具体路径

    2. 打开源文件,创建目标文件

    3. 读取源文件的内容,写入到目标文件中(while)

  • 创建文件夹

    os.mkdir(路径)
    
  • 获取文件夹中的文件列表

    os.listdir(路径)
    
  • 同时打开多个文件并同时写入的方式

    with open(source_path,"rb") as source_file:
           with open(dest_path,"wb") as dest_file:
               while True:
                   file_data = source_file.read(1024)
                   if file_data:
                       dest_file.write(file_data)
                   else:
                       break
    
  • 代码示例:

    import multiprocessing
    import os
    
    def copy_work(source_dir,dest_dir,file_name):
        print(multiprocessing.current_process())
    
        # 拼接源文件的具体路径
        source_path = source_dir + "/" + file_name
        # 拼接目标文件的具体路径
        dest_path = dest_dir + "/" + file_name
        print(source_path,"------>",dest_path)
    
        with open(source_path,"rb") as source_file:
           with open(dest_path,"wb") as dest_file:
               while True:
                   file_data = source_file.read(1024)
                   if file_data:
                       dest_file.write(file_data)
                   else:
                       break
    
    if __name__ == '__main__':
        # 源文件夹所在路径
        source_dir = "./test"
        # 目标文件夹所在路径
        dest_dir = "d:/Users/Jq/Desktop/test"
    
        # 判断文件会否存在
        try:
            os.mkdir(dest_dir)
        except Exception as e:
            print("文件夹已经存在")
    
        # 创建进程池
        pool = multiprocessing.Pool(3)
    
        # 获取文件中的所有文件列表
        file_list = os.listdir(source_dir)
        print(file_list)
    
        # 遍历列表,得到所有的文件名
        for file_name in file_list:
            pool.apply_async(copy_work,(source_dir,dest_dir,file_name))
    
        # 异步方式指定操作
        pool.close()
        pool.join()
    

7.13. 可迭代对象及检测方法

  • 可迭代对象

    # 1.可遍历对象就是可迭代对象
    # 2.列表、元组、字典、字符串都是可迭代对象
    # 3.数值和自定义类默认是不可以迭代的
    # 4.myclass对象所属的类,如果包含了__iter__()方法,就是一个可迭代对象
    # 5.可迭代对象的本质:对象所属的类中包含了__iter__()方法
    
  • 可迭代对象的检测

    • 检测一个对象是否可以迭代,使用isinstance()方法

    • 代码示例:

      from collections.abc import Iterable
      
      ret = isinstance([1,2,3],Iterable)
      print(ret)
      
      ret = isinstance(100,Iterable)
      print(ret)
      
      class MyClass(object):
          # 该方法就是一个迭代器
          def __iter__(self):
             pass
      
      myclass = MyClass()
      ret = isinstance(myclass,Iterable)
      print(ret)
      

7.14. 迭代器及其使用方法

  • 迭代器的作用

    1. 记录当前迭代的位置
    2. 配合next()获取可迭代对象的下一个元素值
  • 获取迭代器

    iter(可迭代对象)
    
  • 获取可迭代对象的值

    next(迭代器)
    
  • for循环的本质

    1. 通过iter(要遍历的对象)获取要遍历对象的迭代器
    2. next(迭代器)获取下一个元素
    3. 捕获Stoplteration异常
  • 自定义迭代器类

    1. 必须含有__iter__()

    2. 必须含有__next__()

      class MyIterator(object):
          def __iter__(self):
              pass
      
      # 当next()迭代器的时候自动调用
      def __next__(self):
          pass
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值