一、如何获取进程的id号和进程的名字.

os.getpid() #获取本进程的id号

os.getppid() #获取本进程的父进程的id号



import os
from multiprocessing import Process
def f1():
    print('f1进程的pid',os.getpid())
    print('f1进程的父进程的pid',os.getppid())
if __name__ == '__main__':
    p1 = Process(target=f1,name='欢迎')
    p1.start()
    print(p1.name)
    print('p1进程的pid',p1.pid)
    print('本进程的id',os.getpid())
# p1.pid #返回结果为p1进程的id号
# os.getpid()#返回本进程的id号
# os.getppid()#返回为本进程的父进程id号
# p1.name()#返回p1进程的名字



 

二、如何手动结束子进程,以及判断子进程是否还在运行

obj.is_terminate()  #给操作系统发送结束进程的信号

obj.is_alive()  #判断进程是否在运行,返回值True,False



import time
from multiprocessing import Process
def f1():
    print('子进程1号')
if __name__ == '__main__':
    p = Process(target=f1,)
    p.start()
    print(p.is_alive())  #判断子进程是否还活着,是否还在运行
    p.terminate() #给操作系统发送一个结束进程的信号
    time.sleep(0.5) #需要延迟一会再判断是否还存活,因为系统结束进程需要处理很多东西
    print(p.is_alive())



 

三、如何验证进程存在空间隔离

对于打印结果的解释:首先程序自上往下走,先打印一遍100,开启子进程后,系统copy一份代码走,并运行,又打印一遍100,子进程修改的只是自己进程里的全局变量,

而父进程的变量还是那个,这就验证了进程之间存在空间隔离.



from multiprocessing import Process
num = 100
def f1():
    global num
    num = 3  #修改全局变量的值
    print('f1进程中的num',num)
print('>>>>>',num)
if __name__ == '__main__':
    p = Process(target=f1,)
    p.start()
    p.join()
    print('主进程中的num',num)
打印结果为:
>>>>> 100
>>>>> 100
f1进程中的num 3
主进程中的num 100



四、关于守护进程



obj(进程的实例化对象).daemon = True       #开启守护进程,一定要在开启进程( obj.start() )前设置
什么是守护进程:
  1.在主进程代码执行结束后就终止(应用场景:子进程需要跟父进程一起结束时)
  2.守护进程内无法开启子进程,否则抛异常



 



from multiprocessing import Process
def f1():
    print("xxx")
def f2():
    print("p普通子进车")
if __name__ == '__main__':
    p = Process(target = f1,)
    p.daemon = True  #开启守护进程,一定要在开启该进程(p.start())前设置,父进程代码执行结束,这个守护进程也结束.
    p.start()
    #p.join()  #给主进程阻塞,守护进程有机会执行里面的代码
    print("主进程结束.")
    p2 = Process(target = f2,) #普通进程不受限制
    p2.start()



五、关于僵尸进程和孤儿进程概念

僵尸进程:在子进程执行完,而主进程还没有执行完的时候,系统会保留执行的子进程一些信息(id号,名字...),它会随着主进程的结束而被清理掉

孤儿进程:主进程在子进程前结束了,这个时候该子进程的一些信息没人管了,就叫孤儿进程,最后会被系统清理.

六、关于互斥锁\进程锁\同步锁:



什么时进程所\互斥锁\同步锁:  控制进程在共享一个文件,或同一个打印终端的时候,产生竞争时的错乱.原理是把并发改成串行
with obj(锁的实例化对象): #简易写法
  需要上锁的代码

Lock.acquire() #加锁
Lock.release() #解锁



 



from multiprocessing import Process,Lock
import time
def show_t(i):
    with open("ticket","r",encoding = "utf-8")as f:  #用with open打开文件,前2个可以用位置参数,但第三个必须用关键字传参
        ticket_data = f.read()
        t_data = eval(ticket_data)
        print("%s查询剩余票数为%s"%(i,t_data["count"]))
def get_t(i,l1):
    # l1.acquire()#加锁
    with l1: #用了该枷锁方法,就不用手动解锁了
        with open("ticket","r",encoding="utf-8")as f:
            ticket_data = f.read()  #ticket票 data数据
            t_data = eval(ticket_data)
        if t_data["count"]>0:
            t_data["count"]-=1
            print("%s抢票成功"%i)
            time.sleep(0.2)
            with open("ticket","w")as f:
                f.write(str(t_data))
        else:
            print("没有票了")
    # l1.release()  #解锁
if __name__ == '__main__':
    l1 = Lock()
    for i in range(10):
        p1 = Process(target=show_t,args=(i,))
        p1.start()
    for i in range(10):
        p2=Process(target=get_t,args=(i,l1)) #传两个参数要加括号
        p2.start()



七、关于multiprocessing包的Queue模块的使用

 



方法介绍:
obj.put()  #往队列里面放数据,如果队列里面满了,会阻塞
obj.put_nowait() #满了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作)
obj.get()   #从队列里面取数据,如果队列里面空了,会阻塞(等待)
obj.get_nowait()    #空了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作)
obj.full()   #查看队列是否满了,满了返回True,但该命令的执行速度比put和get的速度快,所以结果不准确
obj.empty()  #查看队列是否空了,空了返回True,结果同理,有时不准确
obj.qsize()  #返回当前队列内容的长度,结果也不准确



举例:关于Queue



from multiprocessing import Process,Queue
def f1(q):
    q.put('约吗?')
if __name__ == '__main__':
    q = Queue(3)
    p = Process(target=f1,args=(q,))
    p.start()  #开启子进程
    son_p_msg = q.get()  #从队列里面拿数据,队列为空,则阻塞等待
    print('来自子进程的消息:',son_p_msg)



八、JoinableQueue方法(跟Queue相近)



JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
方法介绍:
    q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
        下面例子中,应用此方法目的,是为了解决,当有多个消费者程序,去队列里拿数据的时候,不知道队列里是否空了,而此方法,会往队列里面放入一个信号,表示该数据被拿走了.
    q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止



import time
from multiprocessing import Process,Queue,JoinableQueue
#生产者
def producer(q):
    for i in range(10):
        time.sleep(0.2)
        s = '大包子%s号'%i
        print(s+'新鲜出炉,拿去用')
        q.put(s)
    q.join() #等待的是队列的内容处理完毕(q是队列的实例化对象),而不是等待上面代码执行,就等着task_done()信号的数量,和我put进去的数量相同时,才继续执行下面代码
    print('所有的任务都被处理了,继续潜行吧骚年们')
#消费者
def consumer(q):
    while 1:
        time.sleep(0.5)
        baozi = q.get()
        print(baozi+'被吃了')
        q.task_done()  #给队列发送一个取出的这个任务已经处理完毕的信号
if __name__ == '__main__':
    # q = Queue(30)
    q = JoinableQueue(30) #同样是一个长度为30的队列
    pro_p = Process(target=producer,args=(q,))
    con_p = Process(target=consumer,args=(q,))
    pro_p.start()
    con_p.daemon = True #开启守护进程,消费者会随着主进程的结束而终结
    con_p.start()
    pro_p.join()  #让主进程等待(生产者)子进程
    print('主进程结束')



 九、Manager方法

 



什么是Manager方法:
Manager是是一种数据共享的方法.一种较为高级的多进程通信方式
进程之间的通信:队列、管道、数据共享(Manager). 
  队列,管道,这些方式只适用于多个进程都是源于同一个父进程的情况。如果多个进程不是源于同一个父进程,只能用共享内存,信号量等方式,还有就是数据共享(Manager)
多进程共同去处理共享数据的时候,就和我们多进程同时去操作一个文件中的数据是一样的,不加锁就会出现错误的结果,进程不安全的,所以也需要加锁



 

 

 



import time
from multiprocessing import Process,Manager,Lock #创建进程的方法\数据共享的方法\互斥锁方法
def f1(m_d,l2):
    with l2:
        tmp = m_d["num"]
        tmp -= 1
        time.sleep(0.1)
        m_d["num"]=tmp
if __name__ == '__main__':
    m = Manager()  #实例化数据共享的对象
    l2 = Lock  #实例化锁的对象
    m_d = m.dict({"num":100})
    p_list = []
    for i in range(10):
        p = Process(target=f1,args=(m_d,l2))
        p.start()
        p_list.append(p)
    [pp.join() for pp in p_list]
    print(m_d["num"])