34 进程 pid ppid 并发与并行,阻塞与非阻塞 join函数 process对象 孤儿进程与僵尸进程

进程与程序

一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念

进程来自于操作系统
多进程:多个正在运行的程序.

测试:

import time
while True
time.sleep(1)

多次运行该文件,就会产生多个python.exe进程,可以通过tasklist来查看运行的程序

PID和PPID

pid:系统会给每一个进程分配一个进程编号

验证:

tasklist 用于查看所有的进程信息

taskkill /f /pid pid 该命令可以用于结束指定进程

# 在python中可以使用os模块来获取pid
import os
print(os.getpid())

PPID

当一个进程a开启了另一个进程b时,a称为b的父进程,b称为a的子进程

在python中可以通过os模块来获取父进程的pid

# 在python中可以使用os模块来获取ppid
import os
print("self",os.getpid()) # 当前进程自己的pid
print("parent",os.getppid()) # 当前进程的父进程的pid

如果是在pycharm中运行的py文件,那pycahrm就是这个python.exe的父进程,当然你可以从cmd中来运行py文件,那此时cmd就是python.exe的父进程

进程和程序的区别

程序就是一堆计算机可以识别文件,程序在没有被运行就是躺在硬盘上的一堆二进制

运行程序时,要从硬盘读取数据到内存中,CPU从内存读取指令并执行 ,

一旦运行就产生了进程

一个程序可以多次执行 产生多个进程,但是进程之间相互独立

当我们右键运行了一个py文件时 ,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器

 

阻塞 非阻塞 并行 并发

阻塞 : 程序遇到io操作时就进入了阻塞状态

本地IO input print sleep read write

网络IO recv send

非阻塞: 程序正常运行中 没有任何IO操作 就处于非阻塞状态

阻塞 非阻塞 说的是程序的运行状态

并发: 多个任务看起来同时在处理 ,本质上是切换执行 速度非常快

并行: 多个任务真正的同时执行 必须具备多核CPU 才可能并行

并发 并行 说的是 任务的处理方式

 

 

进程有三种状态

就绪态,运行态,和阻塞态

多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程无法继续执行

进程的创建

但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式

而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4种形式创建新的进程

关于创建的子进程,UNIX和windows

  1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。

  2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的。

进程的销毁

  1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

  2. 出错退出(自愿,python a.py中a.py不存在)

  3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

  4. 被其他进程杀死(非自愿,如kill -9)

process类常用属性
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

    参数介绍:

group参数未使用,值始终为None

target表示调用对象,即子进程要执行的任务

args表示调用对象的位置参数元组,args=(1,2,'egon',)

kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}

name为子进程的名称

方法介绍:

 
1 p.start():启动进程,并调用该子进程中的p.run() 
 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
 3 
 4 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
 5 p.is_alive():如果p仍然运行,返回True
 6. p.exitcode:获取退出码

7 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
 8 p.name:进程的名称

join函数

父进程等待子进程结束后继续执行

案例1:

"""
当你开启了一个子进程 并且给他一个任务 如果你希望知道这个任务什么时候完成 那就需要等待

"""
import  time
from multiprocessing import Process

def task(i):
# print('出去了')
time.sleep(2)
print('%s回来了'%i)

if __name__ == '__main__':
start_time=time.time()
p1=Process(target=task,args=(1,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(3,))


p1.start()
p2.start()
p3.start()



p1.join()
p2.join()
p3.join()

# p3.join()
# p2.join()
# p1.join()


end_time=time.time()
print(end_time - start_time)
print('over')

python中开启子进程的两种方式

方式1:

实例化Process类

from multiprocessing import Process
import time

def task(name):
   print('%s is running' %name)
   time.sleep(3)
   print('%s is done' %name)
if __name__ == '__main__':
   # 在windows系统之上,开启子进程的操作一定要放到这下面
   # Process(target=task,kwargs={'name':'egon'})
   p=Process(target=task,args=('jack',))
   p.start() # 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始状态
   print('======主')

方式2:

继承Process类 并覆盖run方法

from multiprocessing import Process
import time

class MyProcess(Process):
   def __init__(self,name):
       super(MyProcess,self).__init__()
       self.name=name

   def run(self):
       print('%s is running' %self.name)
       time.sleep(3)
       print('%s is done' %self.name)
if __name__ == '__main__':
   p=MyProcess('jack')
   p.start()
   print('主')

需要注意的是

1.在windows下 开启子进程必须放到__main__下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程

2.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管

进程间内存相互隔离

from multiprocessing import Process
import time

name = '千万'


def task():
name = '哇塞'
print('改过了')
print('子进程的%s' % name)


if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(3)
print(name)

孤儿进程与僵尸进程

孤儿进程

孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程

孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。

僵尸进程

僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!

僵尸进程的危害:

由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
在Linux中,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,
在python中,已经封装好了wait操作不需要我们自己清理。
但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。












































原文地址:https://www.cnblogs.com/komorebi/p/10957655.html