组团学

Python进程管理

阅读 (225598)

一、多任务原理

  • 概念

    现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统

  • 什么叫多任务?

    就是操作系统可以同时运行多个任务

  • 单核CPU实现多任务原理

截屏2020011314.49.04.png

  • 多核CPU实现多任务原理

截屏2020011314.48.20.png

  • 实现多任务的方式

    • 多进程模式

      启动多个进程,每个进程虽然只有一个线程,但是多个进程可以一起执行多个任务

    • 多线程模式

      启动一个进程,在一个进程的内部启动多个线程,这样多个线程也可以一起执行多个任务

    • 多进程+多线程

      启动多个进程,每个进程再启动多个线程

    • 协程

    • 多进程+协程

二、进程

1、概念

  • 什么是进程?

    是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体

  • 对于操作系统

    一个任务就是一个进程。比方说打开浏览器就是启动一个浏览器的进程,在打开一个记事本就启动一个记事本进程,如果打开两个记事本就启动两个记事本进程

  • 注意

    进程是系统中程序执行和资源分配的基本单位。每个进程有自己的数据段、代码段和堆栈段

2、使用进程

  • 单进程现象

    import time def run1(): while 1: print("zutuanxue_com is a good man") time.sleep(1) def run2(): while 1: print("zutuanxue_com is a nice man") time.sleep(1) if __name__ == "__main__": run1() # 不会执行run2()函数,只有上面的run1()结束才能执行run2() run2()
  • 启动进程实现多任务

    • multiprocessing模块

      跨平台的多进程模块,提供了一个Process类用来示例化一个进程对象

    • Process类

      作用:创建进程(子进程)

      参数 说明
      target 指定进程执行的任务
      args 给进程函数传递的参数,是一个元组

      注意:此时进程被创建,但是不会启动进程执行

      启动进程:Process对象.start()

    • 示例代码

      import time from multiprocessing import Process def run1(name): while 1: print("%s is a good man"%name) time.sleep(1) def run2(): while 1: print("zutuanxue_com is a nice man") time.sleep(1) if __name__ == "__main__": # 程序启动时的进程称为主进程(父进程) # 创建进程并启动 p = Process(target=run1, args=("kaige",)) p.start() # 主进程执行run2()函数 run2()
  • 主进程负责调度

    主进程主要做的是调度相关的工作,一般不负责具体业务逻辑

    import time from multiprocessing import Process def run1(): for i in range(7): print("zutuanxue_com is a good man") time.sleep(1) def run2(name, word): for i in range(5): print("%s is a %s man"%(name, word)) time.sleep(1) if __name__ == "__main__": t1 = time.time() # 创建两个进程分别执行run1、run2 p1 = Process(target=run1) p2 = Process(target=run2, args=("kaige", "cool")) # 启动两个进程 p1.start() p2.start() # 查看耗时 t2 = time.time() print("耗时:%.2f"%(t2-t1))
  • 父子进程的先后顺序

    主进程的结束不能影响子进程,所以可以等待子进程的结束再结束主进程,等待子进程结束,才能继续运行主进程

    import time from multiprocessing import Process def run1(): for i in range(7): print("zutuanxue_com is a good man") time.sleep(1) def run2(name, word): for i in range(5): print("%s is a %s man"%(name, word)) time.sleep(1) if __name__ == "__main__": t1 = time.time() p1 = Process(target=run1) p2 = Process(target=run2, args=("kaige", "cool")) p1.start() p2.start() # 主进程的结束不能影响子进程,所以可以等待子进程的结束再结束主进程 # 等待子进程结束,才能继续运行主进程 p1.join() p2.join() t2 = time.time() print("耗时:%.2f"%(t2-t1))

3、全局变量在多个子进程中不能共享

import time from multiprocessing import Process money = 100 def run1(): # global money # 在进程中无法使用全局变量 money = 200 print("run1----------------", money, id(money)) for i in range(5): print("zutuanxue_com is a good man") time.sleep(1) def run2(name, word): print("run2----------------", money, id(money)) for i in range(5): print("%s is a %s man"%(name, word)) time.sleep(1) if __name__ == "__main__": t1 = time.time() # 在创建进程时会将主进程的资源拷贝到子进程中,子进程单独有一份主进程中的数据,相互不影响 p1 = Process(target=run1) p2 = Process(target=run2, args=("kaige", "cool")) p1.start() p2.start() p1.join() p2.join() print("main-------------", money) t2 = time.time() print("耗时:%.2f"%(t2-t1))

4、启动大量子进程

# Pool类:进程池类 from multiprocessing import Pool import time import random def run(index): print("子进程 %d 启动"%(index)) t1 = time.time() time.sleep(random.random()* 5+2) t2 = time.time() print("子进程 %d 结束,耗时:%.2f" % (index, t2-t1)) if __name__ == "__main__": print("启动主进程……") # 创建10个子进程执行run功能 # 创建进程池对象 # 由于pool的默认值为CPU的核心数,假设有4核心,至少需要5个子进程才能看到效果 # Pool()中的值表示可以同时执行进程的数量 pool = Pool() for i in range(1, 7): # 创建子进程,并将子进程放到进程池中统一管理 pool.apply_async(run, args=(i,)) # 等待子进程结束 # 关闭进程池:在关闭后就不能再向进程池中添加进程了 # 进程池对象在调用join之前必须先关闭进程池 pool.close() #pool对象调用join,主进程会等待进程池中的所有子进程结束才会继续执行主进程 pool.join() print("结束主进程……")

5、单进程与多进程复制文件对比

  • 单进程复制文件

    import time def copy_file(path, toPath): with open(path, "rb") as fp1: with open(toPath, "wb") as fp2: while 1: info = fp1.read(1024) if not info: break else: fp2.write(info) fp2.flush() if __name__ == "__main__": t1 = time.time() for i in range(1, 5): path = r"/Users/zutuanxue_com/Desktop/file/%d.mp4"%i toPath = r"/Users/zutuanxue_com/Desktop/file2/%d.mp4"%i copy_file(path, toPath) t2 = time.time() print("单进程耗时:%.2f"%(t2-t1))
  • 多进程复制文件

    import time from multiprocessing import Pool def copy_file(path, toPath): with open(path, "rb") as fp1: with open(toPath, "wb") as fp2: while 1: info = fp1.read(1024) if not info: break else: fp2.write(info) fp2.flush() if __name__ == "__main__": t1 = time.time() pool = Pool(4) for i in range(1, 5): path = r"/Users/zutuanxue_com/Desktop/file/%d.mp4" % i toPath = r"/Users/zutuanxue_com/Desktop/file3/%d.mp4" % i pool.apply_async(copy_file, args=(path, toPath)) pool.close() pool.join() t2 = time.time() print("单进程耗时:%.2f"%(t2-t1

6、进程间通信

  • 方式

    • 有名管道
    • 无名管道
    • 队列
    • 共享内存
    • 信号
    • 信号量
  • 代码

    from multiprocessing import Process from multiprocessing import Queue import time def product(q): print("启动生产子进程……") for data in ["good", "nice", "cool", "handsome"]: time.sleep(2) print("生产出:%s"%data) # 将生产的数据写入队列 q.put(data) print("结束生产子进程……") def customer(q): print("启动消费子进程……") while 1: print("等待生产者生产数据") # 获取生产者生产的数据,如果队列中没有数据会阻塞,等待队列中有数据再获取 value = q.get() print("消费者消费了%s数据"%(value)) print("结束消费子进程……") if __name__ == "__main__": q = Queue() p1 = Process(target=product, args=(q,)) p2 = Process(target=customer, args=(q,)) p1.start() p2.start() p1.join() # p2子进程里面是死循环,无法等待它的结束 # p2.join() # 强制结束子进程 p2.terminate() print("主进程结束")

7、封装进程

zutuanxue_comProcess.py

from multiprocessing import Process import time class zutuanxue_comProcess(Process): def __init__(self, name, word): super().__init__() self.name = name self.word = word # 必须叫run,当对象调用start()方法时,默认调用run方法 def run(self): for i in range(5): print("%s is a %s man" % (self.name, self.word)) time.sleep(1)

kaige.Process.py

from multiprocessing import Process import time class KaigeProcess(Process): def __init__(self, name): super().__init__() self.name = name # 必须叫run,当对象调用start()方法时,默认调用run方法 def run(self): for i in range(2): print("%s is a hansome man" % (self.name)) time.sleep(1)

main.py

import time from zutuanxue_comProcess import Zutuanxue_comProcess from kaigeProcess import KaigeProcess if __name__ == "__main__": t1 = time.time() p = Zutuanxue_comProcess("zutuanxue_com", "good") p.start() p.join() p1 = KaigeProcess("kaige") p1.start() p1.join() t2 = time.time() print("耗时:%.2f"%(t2-t1))
需要 登录 才可以提问哦