zoukankan      html  css  js  c++  java
  • 并发编程-多进程

    并发编程-多进程

    1.并发编程

    ​ 并发指的是多个任务同时被执行,并发编程指的是编写支持多任务并发的应用程序。

    2. 进程

    进程指的是正在运行的程序,是一系列过程的统称,也是操作系统在调度和进行资源分配的基本单位.进程是实现并发的一种方式.

    3. 进程与程序

    ​ 进程是正在运行的程序,程序是程序员编写的一堆代码,也就是一堆字符,当这堆代码被系统加载到内存中并执行时,就有了进程。

    需要注意的是:一个程序是可以产生多个进程的,就像我们可以同时运行多个QQ程序一样,会形成多个进程

    4.PID和PPID

    ​ PID:系统会给每一个进程分配一个进程编号即PID,如同人需要一个身份证号来区分。

    验证:

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

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

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

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

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

    5.并发与并行,阻塞与非阻塞

    并发指的是,多个事件同时发生

    例如洗衣服和做饭,同时发生了,但本质上是两个任务在切换,给人的感觉是同时在进行,也被称为伪并行

    并行指的是,多个事件同时进行着

    例如一个人在写代码另一个人在写书,这两件事件是同时在进行的,要注意的是一个人是无法真正的并行执行任务的,在计算机中单核CPU也是无法真正并行的,之所以单核CPU也能同时运行qq和微信其实就是并发执行

    阻塞与非阻塞指的是程序的状态

    阻塞状态是因为程序遇到了IO操作,或是sleep,导致后续的代码不能被CPU执行

    非阻塞与之相反,表示程序正在正常被CPU执行

    补充:进程有三种状态

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

    img

    6.进程相关理论

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

    1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
      2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
      3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
    2. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

     关于创建的子进程,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)

    进程的层次结构

    无论UNIX还是windows,进程只有一个父进程,不同的是:

    1. 在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。
    2. 在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。

    7.Python实现多进程

    1. 实例化Process类
    import os
    
    from multiprocessing import Process
    import time
    
    
    def task(name):
        print('%s is running'%name)	#son is running
        print(os.getpid(),os.getppid())	#12692 17576
    
    if __name__ == '__main__':
        # p = Process(target=task,args=('son',))
        p = Process(target=task,kwargs={'name':'son'})
    
        time.sleep(1)
        p.start()
        print('father process',os.getpid())	#father process,17576
    
    

    linux 与windows开启进程的方式不同

    linux 会将父进程的内存数据 完整copy一份给子进程

    注意:

    ​ windows 会导入父进程的代码 从头执行一遍 来获取需要处理的任务

    ​ 所以在编写代码时如果是windows一定要将开启进程的代码放main判断中

    1. 继承Process类 并覆盖run方法
    from multiprocessing import Process
    import os
    
    #自定义进程对象
    class Downloader(Process):
    
        # def __init__(self,url,size,name):
        #     super().__init__()
        #     self.url = url
        #     self.size = size
        #     self.name = name
    
        def run(self):
            print(os.getpid())
            pass
    
    if __name__ == '__main__':
        m = Downloader()
        m.start()
        print("parent over",os.getpid())
    

    如果需要对进程对象进行高度自定义那就可以继承它

    需要注意的是

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

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

    3.start仅仅是给操作系统发送消息,而操作系统创建进程是要花费时间的,所以会有两种情况发送

    a.开启进程速度慢于程序执行速度,先打印父进程 在打印task中的消息
    
    b.开启进程速度快于程序执行速度,先打印task中的消息,在打印父进程
    

    进程之间内存相互隔离

    from multiprocessing import Process
    import time
    x=1000
    def task():
        global x
        x=0
        print('son',x)
    
    
    if __name__ == '__main_
        print(x)	#1000
        p=Process(target=task)
        p.start()	#son,0
        time.sleep(5)
        print(x)	#1000
    

    join函数的使用

    # join的使用(利用join达到串行的效果)
    from multiprocessing import Process
    import time
    def task1(name):
        for i in range(10):
            print("%s run" % name)
    
    
    if __name__ == '__main__': # args 是给子进程传递的参数 必须是元组
    
    
        ps = []
        for i in range(10):
            p = Process(target=task1,args=(i,))
            p.start()
            ps.append(p)
    
        # 挨个join以下
        for i in ps:
            i.join()
    
        print("over")
    

    进程对对象的常用属性

    from multiprocessing import Process
    def task(n):
        print('%s is running'%n)
    
    if __name__ == '__main__':
        p = Process(target=task,args=('wq',),name = 'liu_jin')
         p.start()       #启动子进程
        print(p.pid)    #18664(获取子进程的pid)
        print(p.name)   #获取子进程名
         p.terminate()   #终止子进程
         p.join()        #提高子进程优先级
        print(p.is_alive()) #获取进程的存活状态(关键在与子进程是(true)否(false)被start)
    
    

    孤儿进程和僵尸进程

    什么是孤儿进程

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

    例如:qq聊天中别人发给你一个链接,点击后打开了浏览器,那qq就是浏览器的父进程,然后退出qq,此时浏览器就成了孤儿进程

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

    什么是僵尸进程

    ​ 僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。该情况仅在linux下出现。windows中进程间完全是独立的没有任何关联。

    如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!

  • 相关阅读:
    Latex学习
    【测试】安卓自动化测试代码片段Java
    【测试】adb(Android debug bridge译名:安卓测试桥)的介绍与常用命令
    【测试】安卓开发中常用的布局和UI元素
    mac终端命令大全
    【测试】使用UIAutomatorViewer做App元素探测工作
    【测试】adb连接夜神模拟器
    mac版本夜神模拟器卡99的解决办法
    mac电脑查看apk文件的包名等信息
    新版macbook pro 取消/恢复开盖启动 revert
  • 原文地址:https://www.cnblogs.com/bruce123/p/11184408.html
Copyright © 2011-2022 走看看