Loading

进程

进程

一:概念梳理

程序:硬盘中的文件.

进程:程序运行起来之后,以进程为单位在内存中.是资源分配的最小单位,将不同程序之间的内存隔离开,数据不会错乱.

线程:是cpu调度的最小单位.

一个进程里面最少一个线程.

计算机就干两个活:IO和运算

cpu切换进程,会把当前线程的数据和状态保存到内存中才会切换到另一个进程.

并发的本质:切换+保存状态+运算

二:python多进程模块

实现多进程两种方式:面向函数  面向对象

无论哪一种其本质都是:如何定义一个任务,然后如何交给一个工具并发的执行任务.

然后是解决效率的问题.

进程用到multiprocessing模块

面向函数:将任务定义在函数中,然后将任务交给进程最后启动就好了

import os
from multiprocessing import Process
import time

def f1(args):
    print(args)
    print("父进程:",os.getppid())
    time.sleep(1)
    print("1")
def f2():
    print("父进程:", os.getppid())# 查看父进程
    time.sleep(1)
    print("2")
if __name__ == "__main__":
    # 将一个函数注册到一个进程当中,一旦start之后就开始调用这个函数
    # 主进程一定会等所有子进程结束了才结束
    #将任务丢到进程中
    #参数有两种方式:
    #1元组一个参数要加,
    #2字典,相当于关键字传参
    #对象是特征与技能的结合体
    p1 = Process(target=f1,args=("传进来的参数",))
    p2 = Process(target=f1,kwargs={"args":"字典传参"})
    p3 = Process(target=f2)
#告诉os开启进程,至于什么时候开启全看os的调度,因此前面创建的进程对象只是传入函数引用,只有开启子进程之后才会调用 p1.start()#异步非阻塞,父进程将开子进程的请求发送到os之后就不管了,继续向下执行,也管不了,因为os负责调度和协调
p2.start() p3.start() print("当前进程号:", os.getpid()) print(__name__) #join方法写在哪个进程中,哪个进程就会等待调用此方法进程的结束才继续执行 # 需求等所有子进程结束了才打印下面的程序结束 p1.join()#同步阻塞,同步只等待p1进程的结束,阻塞只cpu在这里是不工作的,一直等到p1结束之后,cpu才会调度主进程 p2.join() # 前面负责开启进程,是异步执行你无法干预全凭cpu调度,最后join变成同步 # 前面所有子进程结束了,才能输出程序结束 print("程序结束")

主进程会等待所有子进程结束后才结束,负责收尾工作.

守护进程会在主进程结束之后结束.

面向对象:将任务定义在run方法中,创建进程对象之后的start方法会请求os开进程,然后调用run()

import os
from multiprocessing import Process
class MyProcess(Process):
    #参数封装
    def __init__(self,arg1,arg2):
        #之所以要调用父类的初始化方法,是因为父类中的属性子类要用到,例如pid,name,父类中已经做好了,直接拿来用然后封装个性化属性
        super().__init__()
        self.__arg1 = arg1
        self.__arg2 = arg2
    def run(self):
        #把运行逻辑写到run方法里面就可以了
        #此时的参数通过在父进程创建此类的对象,通过init把参数接收进来,到run中执行拿到的参数
        print(os.getpid())#在父类中查看进程id只能用os模块
        print(self.name)#父类封装了name属性
        print(self.pid)#父类封装了pid属性
        print(self.__arg1,self.__arg2)

if __name__ == "__main__":
    p1 = MyProcess(1,2)
    p2 = MyProcess(3,4)
    p1.start()
    p2.start()

除了例子中的属性外,父类还封装了方法,可以直接拿来使用

#p.terminate()发指令给os终止子进程,并不能立刻终止,可以你发完此命令在判断isalive()子进程还活着
#p.isalive()判断子进程是否还活着
#这两个方法都是在父类里面调用的,因为父进程开的子进程,子进程引用在父进程手里握着,并不是子进程来调用的.
#p.pid主进程里看子进程id号,在子进程中看只能用os.getpid()看 #父进程中直接打印进程的pid属性即可 ####僵尸进程和孤儿进程 #主进程代码执行完会等待子进程运行结束才会结束 #父进程开子进程,运行角度看是完全独立,没有任何关系 #僵尸进程:进程运行结束之后,保存他的pid,使用了多少内存等这些信息,为了让父进程无论什么时候都能看到这些信息 #僵尸进程是有害的占用着pid号,一旦到了边界,再就开不了进程 #所以如果主进程在子进程消亡后还有很长一段时间不会死掉,那么就会产生大量僵尸进程占用进程号 #因此如果出现这种情况,应在主进程长时间等待过程中,是子进程已经结束后再调用join()把子进程回收掉 #而不是让主进程阻塞等待子进程结束,而是子进程已经结束了,再join() #这样父进程能够在它或者的时候任意看到子进程的信息,但是父进程不知道子进程什么时候死掉 #为了父进程无论子进程或者还是死掉,把子进程消失后的信息还是会保存下来,直到父进程也消失才会全部消失在内存 #父进程死了之后为儿子进程收尸,只要父进程不死随时可以看儿子进程的信息 #所以所有的子进程都会进入僵尸进程 ###孤儿进程 #儿子没死,父进程先死了,子进程就会变成孤儿进程,由政府进程linux中的init进程,进程号为0来回收 #之前的join()方法就是父进程在等待子进程死亡为其收尸,但在它没死亡之前不会影响他们的运行和并发

 三:进程锁

并发时涉及到不同进程数据的修改,此时需要加锁来保证数据的安全,虽然效率会降低,但是必须以数据安全为前提.

具体代码放到下一章节

posted @ 2019-10-05 16:26  浅忆尘  阅读(92)  评论(0)    收藏  举报