python学习笔记(十六)进程使用
进程使用
文章目录
进程简介
什么是进程(任务)?
在计算机中,一个进程就是一个任务,其实就是运行着的程序。
在操作系统中,进程就是程序执行和资源分配的基本单元。
单核CPU实现多任务
将CPU的时间快速的切换和分配到不同的任务上
若频率足够高,切换足够快,人的感官就无法感知
多核CPU实现多任务
如果任务数量不超过CPU数量,完全可以一个核心做一件事
在操作系统中几乎是不可能,通常任务数量都远远大于CPU数量
同样可以采用轮流分配的方式实现多任务,只是同事干活的’人’是多个罢了
为什么使用多进程?
在一个程序中,若出现耗时操作,程序就会出现阻塞(假死),为了解决这种问题可以采用多进程进行解决。如:主进程负责管理工作,子进程负责做耗时操作。
进程管理
简单示例:
import os
import multiprocessing
import time
def do_something(*args, **kwargs):
print('子进程开始')
# 获取当前进程
current_process = multiprocessing.current_process()
print(current_process.pid, current_process.name)
# 获取当前进程及父进程ID
print(os.getpid(), os.getppid())
print('args:', args)
print('kwargs:', kwargs)
time.sleep(5)
print('子进程结束')
# 启动子进程后,系统会拷贝当前代码并加载执行
# 创建并启动子进程操作将无限循环进行下去
# 放在下面的结构中可以解决这个问题
if __name__ == '__main__':
print('主进程开始')
# 获取当前进程号
print(os.getpid())
# 获取当前进程
current_process = multiprocessing.current_process()
print('进程ID:', current_process.pid)
print('进程名称:', current_process.name)
# 创建进程
# target:指定进程任务,其实就是一个函数
# name:指定进程名称
# args:传递给进程函数的位置参数,是一个元组
# kwargs:传递给进程函数的关键字参数,是一个字典
p = multiprocessing.Process(target=do_something, args=(1, 2, 3), kwargs={'age': 18},name='LoopProcess')
# 设置子进程随主进程结束而结束,默认为False
p.daemon = True
# 启动进程
p.start()
# 等待子进程结束
# p.join()
time.sleep(1)
# 手动结束子进程
p.terminate()
print('主进程结束')
进程锁:限制资源只能被一个进程使用
import multiprocessing
import time
from random import random
def loop(lock):
# 获取锁
lock.acquire()
current_process = multiprocessing.current_process()
print(current_process.name, '开始')
time.sleep(random() * 5)
print(current_process.name, '结束')
# 释放锁
lock.release()
if __name__ == '__main__':
# 创建一个进程锁
lock = multiprocessing.Lock()
lt = []
for i in range(1, 6):
p = multiprocessing.Process(target=loop, args=(lock,), name='子进程'+str(i))
lt.append(p)
p.start()
for p in lt:
p.join()
# 为什么在调用子进程的时候是随机的而不是按照生成的顺序???
信号量:限制某个资源最多可以被多少个进程同时使用
import multiprocessing
import random
import time
def run(name, se):
# 获取信号量
se.acquire()
print(name, '进程开始')
time.sleep(random.random()*3)
print(name, '进程结束')
# 释放信号量
se.release()
if __name__ == '__main__':
# 创建一个信号量对象,需要指定上限
se = multiprocessing.Semaphore(3)
for i in range(1, 10):
p = multiprocessing.Process(target=run, args=('num'+str(i), se))
p.start()
进程池 简化进程的管理 统一管理 可以设置回调
import multiprocessing
import random
import time
# 进程任务结束的回调函数,参数时进程函数的返回值
def callback(num):
print(num, '进程回调函数')
def task(num):
print(num, '开始')
t = random.random() * 3
time.sleep(t)
print(num, '进程执行了{}秒'.format(t))
print(num, '结束')
return num
if __name__ == '__main__':
print('主进程开始')
# 获取CPU核心数
cpu_count = multiprocessing.cpu_count()
# print(cpu_count)
# 创建进程池:容量一般不超过CPU核心数
pool = multiprocessing.Pool(cpu_count)
# 循环创建进程,然后添加到进程池
for i in range(1, 6):
# 向进程池添加进程
# func:进程任务,一个函数
# args:以元组形式传递给进程函数的参数
# kwargs:以字典形式传递给进程函数的参数
pool.apply_async(func=task, args=(i,), callback=callback)
# 关闭进程池,之后就不能再添加进程了
pool.close()
# 等待进程池结束
pool.join()
print('主进程结束')
数据共享
全局变量:无法在多个进程之间共享
import multiprocessing
# 多进程之间不能进行全局变量共享
num = 100
def run():
global num
print('子进程开始')
num += 10
# print('子进程:', num)
print('子进程结束')
if __name__ == '__main__':
print('主进程开始')
p = multiprocessing.Process(target=run)
p.start()
p.join()
print('主进程结束', num)
管道
import multiprocessing
def run(p_a):
# 子进程接收数据
recv = p_a.recv()
print('子进程接收到数据:', recv)
# 子进程发送数据
p_a.send('world')
print('子进程结束')
if __name__ == '__main__':
# 创建管道
# duplex:是否是全双工,默认为True
# 半双工:p_a只能接收数据,p_b只能发送数据
p_a, p_b = multiprocessing.Pipe()
# 创建子进程
p = multiprocessing.Process(target=run, args=(p_a,))
p.start()
# 主进程发送数据
p_b.send('hello')
p.join()
# 主进程接收子进程发来的数据
print('主进程结束', p_b.recv())
队列
import multiprocessing
if __name__ == '__main__':
# 创建一个队列,指定容量
q = multiprocessing.Queue(3)
# 判断是否为空
print(q.empty())
# 向队列中添加数据
q.put('how')
q.put('are')
q.put('you')
# 判断是否已满
print(q.full())
# 若队列已满,再放数据则会阻塞
# q.put('hello')
# 若队列已满,则会崩溃
# q.put_nowait('hello')
# 获取数据
print(q.get())
# print(q.qsize())
print(q.get())
print(q.get())
# 若队列已空,再获取数据会阻塞
# print(q.get())
# 若队列已空,再获取数据会崩溃
# print(q.get_nowait())
# 队列长度(队列中的数据数量)
print(q.qsize())
# 队列关闭
q.close()
自定义进程类
说明:将进程处理封装成类,要求继承自multiprocessing.Process
示例:
from multiprocessing import Process
import time
class DownloadProcess(Process):
def __init__(self, file):
super().__init__()
self.file = file
# 在调用start方法后会自动调用
# 改方法就是进程任务,无需单独指定
def run(self):
print('{}文件开始下载'.format(self.file))
for i in range(1, 6):
time.sleep(1)
print('进度{}%'.format(i * 20))
print('{}文件下载完成'.format(self.file))
if __name__ == '__main__':
print('主进程开始')
dp = DownloadProcess('meinv.jpg')
dp.start()
dp.join()
print('主进程结束')