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. 进程-基本使用
- 进程使用的步骤:
-
导入模块
import multiprocessing
-
创建子进程对象
process_obj = multiprocessing.Process(target=work1)
-
启动子进程
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. 进程-参数传递、全局变量问题
-
进程的参数传递
-
args元组
process_obj = multiprocessing.Process(target=work1,args=(10,100,1000))
-
kwargs字典
process_obj = multiprocessing.Process(target=work1,kwargs={"c":10,"b":100,"a":1000})
-
混合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器(多进程版)
-
思路
- 定义变量,保存源文件夹、目标文件夹所在的路径
- 在目标路径创建新的文件夹
- 获取源文件夹中的所有的文件(列表)
- 遍历列表,得到所有的文件名
- 定义函数,进行文件拷贝
-
文件拷贝函数
参数:源文件夹路径 目标文件夹路径 文件名
-
拼接源文件和目标文件的具体路径
-
打开源文件,创建目标文件
-
读取源文件的内容,写入到目标文件中(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. 迭代器及其使用方法
-
迭代器的作用:
- 记录当前迭代的位置
- 配合
next()
获取可迭代对象的下一个元素值
-
获取迭代器
iter(可迭代对象)
-
获取可迭代对象的值
next(迭代器)
-
for循环的本质
- 通过
iter(要遍历的对象)
获取要遍历对象的迭代器 next(迭代器)
获取下一个元素- 捕获
Stoplteration
异常
- 通过
-
自定义迭代器类
-
必须含有
__iter__()
-
必须含有
__next__()
class MyIterator(object): def __iter__(self): pass # 当next()迭代器的时候自动调用 def __next__(self): pass
-