进程与子进程补漏及守护进程与互斥锁的概念

1.上节课补漏

把原来在父进程中串行的任务分配到子进程中,实现并发。
看下上节课复习例题
子进程方式二的run()固定的
进程id号是一个进程在操作系统里的身份证号
僵尸进程:占据pid未回收,其他系统资源回收了
join()里面有wait 等到子进程执行完毕,将子进程占用操作系统的pid回收
开启一个子进程时会给他一个pid,回收的是操作系统所占的pid号,而不是子进程属性里的pid,子进程结束后依然可以查看他的pid。

from multiprocessing import Process
import time
import os

def task():
    print('%s is running' %os.getpid())
    time.sleep(3)
    print('%s is done' % os.getpid())

if __name__ == "__main__":
    p=Process(target=task)
    p.start() # 仅仅只是向操作系统发送一个开启进程的信号
    print(p.pid)

    p.join() # 等到子进程p执行完毕后,将p占用的操作系统的pid回收
    time.sleep(2)
    print(p.pid) # 依然可以查看他的pid 回收的是他在操作系统所占的pid号 他自己属性里也有


    print('')
子进程回收以后pid查看

僵尸进程目的:为了让父进程随时可以拿到子进程pid。
出现大量僵尸进程处理:直接杀死父进程
谁开了谁就是他的父进程:比如cmd运行一个py文件 cmd就是父进程
杀死父进程cmd,父进程cmd并未关闭窗口是因为cmd被当作终端在输出,如何关闭?

2.守护进程
一定要放在p.start()之前
守护进程其实就是一个“子进程”,
守护=》伴随
守护进程会伴随主进程的代码运行完毕而死掉。

为何要用守护进程?
守护:该子进程内的代码在父进程代码运行完毕后就没有存在意义了,就应该将该进程设置为守护进程,会在父进程代码结束后死掉。
进程:当主进程需要把任务并发出去执行,需要把该任务放到一个子进程里。

子进程·daemon = True 表示该进程未守护进程,这段代码一定要放在start之前
from multiprocessing import Process
import time,os

def task(name):
    print('%s is running' %name)
    time.sleep(3)

if __name__ == '__main__':
    p1=Process(target=task,args=('守护进程',))
    p2=Process(target=task,args=('正常的子进程',))

    p1.daemon = True # 一定要放到p.start()之前
    p1.start()
    p2.start()

    print('')
守护进程

注意:守护进程结束的时间是主进程最后一行代码完全执行完毕,如果有输出就是最后一个字符打印到终端才算结束。

计算机性能越好,开启子进程速度越快,输出可能就不一样,详情见下面的代码。

#主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------")

    '''
    main-------
    456
    enn456
    '''


    '''
    main-------
    123
    456
    enn456
    '''

    '''
    123
    main-------
    456
    end456
    '''
不同计算机配置对输出的影响

 



3.进程的互斥锁
mutex 互斥的意思 mutex = Lock()
文件是进程可以共享的
原理:将并发变成串行,保证数据安全
互斥锁不能连续acquire,只能release再acquire
join才是真正的串行
互斥锁是谁优先抢到锁谁执行共享数据代码,其他部分该并发还是并发。
互斥锁:可以将要执行部分的任务代码(只涉及到修改共享数据的代码)变成串行。
join:是要执行任务的所有代码串行。

mutex.acquire()
需要串行的程序
mutex.release()
被锁起来的程序只能一个个进入。

#互斥锁:可以将要执行任务的部分代码(只涉及到修改共享数据的代码)变成串行
#join:是要执行任务的所有代码整体串行
from multiprocessing import Process,Lock  # 需要导入互斥锁对应的类
import json
import os
import time
import random

# 模拟抢票的流程:查看票和购买票
def check():
    time.sleep(1) # 模拟网路延迟
    with open('db.txt','rt',encoding='utf-8') as f:
        dic=json.load(f)
    print('%s 查看到剩余票数 [%s]' %(os.getpid(),dic['count']))

def get():
    with open('db.txt','rt',encoding='utf-8') as f:
        dic=json.load(f)
    time.sleep(2)
    if dic['count'] > 0:
        # 有票
        dic['count']-=1
        time.sleep(random.randint(1,3))
        with open('db.txt','wt',encoding='utf-8') as f:
            json.dump(dic,f)
        print('%s 购票成功' %os.getpid())
    else:
        print('%s 没有余票' %os.getpid())


def task(mutex):
    # 查票
    check()

    #购票
    mutex.acquire() # 互斥锁不能连续的acquire(获得),必须是release以后才能重新acquire
    get()
    mutex.release()



    # with mutex:  # 可以用这种表达方式,自动释放
    #     get()

if __name__ == '__main__':
    mutex=Lock()
    for i in  range(10):
        p=Process(target=task,args=(mutex,))
        p.start()
        # p.join()
互斥锁

 









posted @ 2018-07-12 15:50  Roc_Atlantis  阅读(182)  评论(0编辑  收藏  举报