进程
一、概念
1.概念
进程: 通俗理解一个运行的程序或者软件,进程是操作系统资源分配的基本单位。
注意: 一个程序至少有一个进程,一个进程至少有一个线程,多进程可以完成多任务.
2.进程的执行状态
工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
- 就绪态:运行的条件都已经慢去,正在等在cpu执行
- 执行态:cpu正在执行其功能
- 等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
二、进程的创建和操作
1.进程的创建
创建进程 :
开始执行 : pro.start()
2.进程的操作
pro.join(2) 阻塞等待子进程2秒 如果子进程没有终止那主进程就直接往下执行
pro.terminate() 终止子进程
pro.is_alive() 判断子进程状态
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:Mr.yang import multiprocessing import time import os def pro_info(info, data): """子进程 运行的代码""" for i in range(30): print("这是子进程 info=%s data=%s PID=%s PPID=%s" % (info,data,os.getpid(),os.getppid())) time.sleep(1) def main(): """单进程 单线程模式 主进程""" # 创建子进程 pro = multiprocessing.Process(target=pro_info, args=("今天天气不错",), kwargs={"data":"50"}, name="陈特特") # 创建 启动子进程 pro.start() # 主进程阻塞等待子进程 2秒 / 如果能等到子进程退出 回收子进程的资源 pro.join(2) print("获取子进程的pid = %s name = %s" % (pro.pid,pro.name)) print("===============================") # 判断子进程是否存活 print(pro.is_alive()) # # 终止子进程 像操作系统发出一个 终止子进程的信号 存在延迟 不要立即判断子进程的状态 # pro.terminate() # 判断子进程是否存活 print(pro.is_alive()) print("===============================") for i in range(3): # 查看当前所在进程的PID print("这是主进程 PID=%s" % os.getpid()) time.sleep(1) if __name__ == '__main__': main()
三、进程通信--Queue
1.使用队列Queue的原因
原因: 进程间不共享全局资源
Queue 是一种进程间通信的方式, 先进先出
2.使用方法
- 创建 队列对象 = multiprocessing.Queue(长度)
- 放 队列对象.put(数据)
- 取 数据 = 队列对象.get()
- 判断空 队列对象.empty()
- 判断满 队列对象.full()
- 数量 队列对象.qsize()
import multiprocessing import time def proc_func(q): """子进程入口""" while True: time.sleep(3) # 判断空 if q.empty(): print("队列中已经没有了 稍后再来") time.sleep(3) # 从队列中取出数据 data = q.get() print("从队列中取出了数据%s" % data) def main(): pass # 1 创建出来 主进程和子进程通信所需的 队列对象 q = multiprocessing.Queue(3) # 2 创建子进程 pro = multiprocessing.Process(target=proc_func, args=(q,)) pro.start() while True: # 3 接收输入 放入队列中 data = input(":") # 判断队列满 if q.full(): print("慢点输入已经满了 马上溢出了") time.sleep(1) # 向队列中放入数据 q.put(data) if __name__ == '__main__': main()
四、进程池
1.工作模式
模式 : 重复利用已经空闲的进程执行 多任务
优点 : 提高任务的响应速度
2.添加任务两种方式
会阻塞等待添加任务的执行完成后才会继续往下执行
异步方式 :只添加任务 不会等待任务执行完成
3.使用步骤和注意事项
1 创建进程池 进程池对象 = multiprocessing.Pool(工作进程的数量) 2 添加任务 同步 进程池对象.apply(入口) 添加任务并等待任务执行完成 异步 进程池对象.apply_async(入口) 只添加任务 不等待任务完成 3 关闭进程池 进程池对象.close() 不允许添加新任务 4 等待所有任务执行完成 进程池对象.join()
注意:
五、进程与线程区别
1.区别
- 进程之间不共享全局变量
- 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
- 线程不能够独立执行,必须依存在进程中
- 多进程开发比单进程多线程开发稳定性要强
2.优缺点
多进程:
-
-
- 优点:可以用多核
- 缺点:资源开销大
-
多线程:
-
-
- 优点:资源开销小
- 缺点:不能使用多核
-
3.功能对比
-
- 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
- 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口
4.定义对比
-
- 进程是系统进行资源分配基本单位,每启动一个进程操作系统都需要为其分配运行资源。
- 线程是运行程序中的一个执行分支,是CPU调度基本单位。
- 总结:进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
六、案例
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:Mr.yang import multiprocessing import os def copy_file(src_path, dest_path, file): """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中""" # 1.打开源目录下的文件用以读 src_file = open(src_path + "/" + file, "rb") print(dest_path + "/" + file) # 2.打目的目录下的文件用以写 dest_file = open(dest_path + "/" + file, "wb") # 3.一遍从源文件中读取数据 写入目的文件中 while True: file_data = src_file.read(1024) if not file_data: print("%s文件拷贝完成" % file) break dest_file.write(file_data) # 4.完成后 关闭源文件 关闭目的文件中 src_file.close() dest_file.close() def main(): # 1.用户输入备份的目录 source_path = input("请输入要备份的目录:") # 2.根据源目录创建一个目的目录 源目录-备份 dest_path = source_path + "-备份" os.mkdir(dest_path) # 3.根据源目录去获取源目录下所有的 文件名称 file_list = os.listdir(source_path) # print(file_list) # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件 for file in file_list: pro = multiprocessing.Process(target=copy_file, args=(source_path, dest_path, file)) pro.start() if __name__ == '__main__': main()
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:Mr.yang import multiprocessing import time import os def copy_file(src_path, dest_path, file, q): """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中""" # 1.打开源目录下的文件用以读 src_file = open(src_path + "/" + file, "rb") # 2.打目的目录下的文件用以写 dest_file = open(dest_path + "/" + file, "wb") # 3.一遍从源文件中读取数据 写入目的文件中 while True: file_data = src_file.read(1024) if not file_data: # print("%s文件拷贝完成" % file) break dest_file.write(file_data) # 4.完成后 关闭源文件 关闭目的文件中 src_file.close() dest_file.close() # 5.当任务完成后 向队列中添加一个消息 表示完成 q.put(file) def main(): # 1.用户输入备份的目录 source_path = input("请输入要备份的目录:") # 2.根据源目录创建一个目的目录 源目录-备份 dest_path = source_path + "-备份" os.mkdir(dest_path) # 3.根据源目录去获取源目录下所有的 文件名称 file_list = os.listdir(source_path) # print(file_list) # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件 # 使用进程池处理每个任务 # 4.0 创建出一个队列 用于进程间通信 不能使用multiprocessing.Queue(10) # q = multiprocessing.Queue(10) q = multiprocessing.Manager().Queue(10) # 4.1 创建进程池 p = multiprocessing.Pool(4) # 4.2 添加任务到进程池中 for file in file_list: p.apply_async(copy_file,args=(source_path, dest_path, file, q)) # 4.3 关闭进程池 p.close() # 从队列中取出消息 count = 0 while True: if count == len(file_list): break q.get() count += 1 print(" 当前进度是%.2f %%" % ((count/len(file_list))*100), end="") time.sleep(0.1) # 4.4 等待进程池所有任务都执行完成 p.join() if __name__ == '__main__': main()