zoukankan      html  css  js  c++  java
  • 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操作不需要我们自己清理。
    但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。












































  • 相关阅读:
    cf B. Sereja and Suffixes
    cf E. Dima and Magic Guitar
    cf D. Dima and Trap Graph
    cf C. Dima and Salad
    最短路径问题(floyd)
    Drainage Ditches(网络流(EK算法))
    图结构练习—BFSDFS—判断可达性(BFS)
    Sorting It All Out(拓扑排序)
    Power Network(最大流(EK算法))
    Labeling Balls(拓扑)
  • 原文地址:https://www.cnblogs.com/komorebi/p/10957655.html
Copyright © 2011-2022 走看看