进程
1. 什么是进程
一个学校里面有很多不同的学院,他们都是相互独立,教学内容也不一样,但都是属于学校。
程序运行的进程为父进程,在父进程下创建的都为子进程,父进程结束,则所有的子进程也会结束。
子进程直接相互独立不干扰,都有相对应的进程号,在资源方面不共享,相对进程资源管理更加简易,但是会占用CPU内存。
2. Linux下命令符对进程的操作
2.1 ps 查看当前运行的进程
ps -a 在终端上显示所有用户的进程,包括其他用户
ps -u 查看进程的详细信息状态
ps -显示没有终端控制的进程
ps -j 显示作业控制的相关进程,可查看父进程
ppid 为父进程id
pid 为进程id
kill发出指令要求进程死亡
sudo kill pid 以超级用户权限杀死进程
kill -9 pid 强制杀死
3. 进程的状态
死亡态, 运行态,等待(阻塞)态,就绪态,新建
4 创建进程
首先导入multiprocessing模块
p=multiprocessing.Process(group=None,target=None,name=None,args=(),kwar
s={},,daemon=None)
import multiprocessing
def course(str):
print(str)
# 启动进程
str = "hello world"
p1 = multiprocessing.Process(target=course, args=(str, ))
# 启动进程
p1.start()
4.1 创建进程的参数
group
:指定进程组,大多数情况下用不到
target
:如果传递了函数的引用,可以任务这个子进程就执行这里的代码
name
:给进程设定一个名字,可以不设定
args
:给target指定的函数传递的参数,以元组的方式传递
kwargs
:给target指定的函数传递命名参数
daemon
:是否以守护进程运行,True 或False
4.2 进程的方法
start()
开始进程
is_alive()
判断线程是否存活
join([timeout])
是否等待子进程执行结束,或者等待多少时间
import multiprocessing
def course(str):
print(str)
# 启动进程
str = "hello world"
p1 = multiprocessing.Process(target=course, args=(str, ))
# 判读进程是否存活
print("线程未启动时,是否存活:", p1.is_alive())
# 启动进程
p1.start()
# 线程已开始
print("线程启动时,是否存活:", p1.is_alive())
线程未启动时,是否存活: False
线程启动时,是否存活: True
hello world
5. 线程和进程的区别
5.1 线程
线程是一个进程下,同时实现多个任务,共享全局变量,因为是在一个进程下,所以占用系统资源小,容易造成资源抢夺
5.2 进程
进程是相互独立的存在,每个进程都有对应的进程号,相当于再开辟出一个内存空间进行运行,进程之间全局变量不共享。多进程相对多线程更加消耗系统资源,但是在资源上能够更好的处理
6.进程池
6.1 进程池的作用
进程池可以消耗最小的系统内存和时间处理大量的系统操作.
如果没有线程池。在需要处理上百或者上千条线程则需要同时创建成百上千个线程,而这是不太现实的,即使能够创建,也会浪费大量的时间在创建线程,消灭进程中。
使用线程池处理大量并发线程,可以使用最小的系统占用内存,处理更多的线程,在创建的线程池的线程中,不断循环使用,而不关闭线程,这样可以做到,反复利用,加快运行效率,也避免了同时创建大量的线程导致的系统崩溃
6.2 创建进程池
首先导入multiprocessing.Pool()
apply_async(方法(参数))
线程池创建线程方法
close()
关闭线程池,不再创建线程,但是会将之前的线程运行结束
join()
主进程等待子进程结束后再结束,会堵塞至子进程结束,必须写在close()或terminate()后使用,如果不使用join()主进程会直接结束。如:亲子赛跑,父亲先到达终点后,会继续前进然后停止,使用了join后父亲会在终点处等待孩子们都到达终点后再结束
import multiprocessing, time, os
def course(str):
# 进程开始时间
start_time = time.time()
print("进程: %s,我的进程号为:%d , 我的父进程号为:%d" % (str, os.getpid(), os.getppid()))
# 结束时间
end_time = time.time()
print("进程%s, 消耗时间:%.5f," % (str, (end_time - start_time)))
# 让进程休眠0.5s再运行
time.sleep(0.5)
list_str = ["python", "c", "java"]
# 创建进程池, 数量为两个
po = multiprocessing.Pool(3)
for str in list_str:
# 向进程池添加任务
po.apply_async(course, (str,))
print("hello")
# 关闭进程池
po.close()
# 父进程等待子进程结束后结束
po.join()
hello
hello
hello
进程: python,我的进程号为:6412 , 我的父进程号为:6411
进程python, 消耗时间:0.00007,
进程: c,我的进程号为:6413 , 我的父进程号为:6411
进程c, 消耗时间:0.00011,
进程: java,我的进程号为:6414 , 我的父进程号为:6411
进程java, 消耗时间:0.00005,
如果不添加join()方法,则效果如下
hello
hello
hello
6.3进程间的通信
6.3.1 为什么需要进程间的通信
进程中全局变量是不同享的,无法进程沟通,导致对应数据无法传输。
进程之间相互独立运行,但是也需要进行沟通通信合作,如:QQ和QQ音乐两个进程之间的通信。
进程之间的通信方便了资源的处理,有利于进程之间的运行
7.Queue队列
-
multiprocessing.Queue()
创建消息队列
部分mac电脑必须multiprocessing.Manger().Queue()
创建进程池的消息队列,在进程池中使用消息队列必须使用此方法,否则会抛出异常 -
from queue import Queue
系统自带消息队列模块不能进行线程之间的通信,属于各自线程私有 -
put(msg, [block[,timeout]])
存入消息, 使用默认block值为True,timeout设置如果消息队列已满,经过多久时间后再次尝试,如果时间到了没有空位则会抛出异常Queue,Full。如果未设置时间,队列为满则会出现堵塞状态,一直到消息队列出现空位为止。block设置为False,如果消息队列已满则会立即抛出异常Queue.Full -
get()
释放消息 -
qsize()
或者当前队列的消息数量 -
empty()
如果队列为空则返回False, 反之则返回True。系统在添加队列事有一定延迟,最后在添加完后睡眠0.5s左右,以保证empty()
能够正常判读 -
full()
如果队列为空则返回True, 反之则返回False -
put_nowait
() 如果消息队列已满,则抛出异常,Queue.Full ,相当于put(msg,False)
import multiprocessing, time
# 创建消息队列,为三条
q = multiprocessing.Queue(3)
# 存入消息
q.put('我是第一条消息')
q.put('我是第二条消息')
q.put('我是第三条消息')
time.sleep(0.5)
try:
q.put("我是第四条消息", False)
except BaseException :
print("消息队列已满")
# 判断消息队列是否为空
print("empty", q.empty())
print("full", q.full())
# 打印当前消息数量
print("当前一共有:%d条消息" %q.qsize())
print(q.get())
print(q.get())
print(q.get())
# 打印当前消息数量
print("当前一共有:%d条消息" %q.qsize())
print("empty", q.empty())
print("full", q.full())
消息队列已满
empty False
full True
当前一共有:3条消息
我是第一条消息
我是第二条消息
我是第三条消息
当前一共有:0条消息
empty True
full False
本文还有很多不足,如有更好的意见或者有什么遗漏欢迎大家补充,第一次用MarkDown编辑器,可能在观赏上有点不太美观,望谅解。会持续更新自己的学习心得,大家可以一起来交流