• Python学习笔记-Day33-进程


    内容大纲:

    一、用python开启进程的两种方式

    二、join控制子进程

    三、daemon守护进程

    四、Lock锁

    五、Semaphore信号量

    六、Event事件

    一、用python开启进程的两种方式

    multiprocessing包:是python中一个用于操作、管理进程的包,这个包几乎包含了进程有关的所有的子模块。大致可分为四个部分:创建进程部分、进程同步部分、进程池部分、进程之间数据共享部分。

    multiprocessing.Process模块是专门用来创建进程的模块

    1、直接使用Process类创建一个进程


    import
    os import time from multiprocessing import Process def func(): for i in range(10): time.sleep(0.5) print('子进程',os.getpid(),os.getppid()) if __name__ == '__main__': print('主进程',os.getpid(),os.getppid()) p = Process(target=func) # 实例化一个进程对象 p.start() # 子进程开始 for i in range(10): print('*'*i)

    注意:为什么要用if __name__ == '__main__':

    在windows操作系统中由于没有fork(linux操作系统在创建进程的机制),在创建子进程的时候会自动import启动它的这个文件,而在import的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归子进程报错。所以必须把创建子进程的部分使用if __name__ == '__main__'判断保护起来,import的时候就不会递归运行了。

    主进程与子进程之间的关系:

    ① 父进程和子进程的启动是异步的

    ② 父进程在执行完毕后不会立即结束程序,而是会等所有的子进程结束,父进程负责回收子进程的资源

    # 创建多个子进程和给子进程传参
    import  os
    from multiprocessing import Process
    def func(index):
        print('子进程%s:'%index,os.getpid(),os.getppid())
    if __name__ == '__main__':
        for i in range(10):  # 创建多个子进程
            p = Process(target=func,args=(i,))  # 给子进程传参
            p.start()
        print('主进程:',os.getpid(),os.getppid())
    #主进程与子进程之间数据是隔离的
    from multiprocessing import Process
    count = 100
    def func():
        global count
        count -= 1
        print('子进程:',count)
    if __name__ == '__main__':
        print('主进程:',count)
        p = Process(target=func)
        p.start()
    结果:
    99
    100

    2、用自定义类开启子进程

    ① 自定义一个类

    ② 继承Process

    ③ 一定要实现run()方法

    ④ 要传参数时,首先调用Proces中的init()方法才能进行传参

    import os
    from multiprocessing import Process
    class Myprosess(Process):
        def __init__(self,arg):
            super().__init__()
            self.arg = arg
        def run(self):
            print('子进程%s:'% self.arg,os.getpid(),os.getppid())
    if __name__ == '__main__':
        for i in range(10):
            p = Myprosess(i)
            p.start()
        print('主进程:',os.getpid(),os.getppid())

    二、join控制子进程

    join的作用:主进程的任务执行到某个阶段,需要等待子进程执行完毕后才能继续执行,否则就进入阻塞状态。没有join的时候,子进程和主进程的发生顺序是不可与预测的。

    例如:模拟发邮件

    import time
    import random
    from multiprocessing import Process
    def func(index):
        time.sleep(random.random())
        print('第%s邮件已发送'%index)
    if __name__ == '__main__':
        p_lst = []
        for i in range(10):
            p = Process(target=func,args=(i,))
            p.start()
            p_lst.append(p)
        for p in p_lst:
            p.join()
        print('10封邮件已全部发送完毕')

    三、deamon守护进程

    将一个子进程设置为守护进程之后

    1、守护进程会随着主进程代码的执行完毕而结束

    2、如果主进程的代码已经执行完,但是还有一些子进程还没执行完,主进程会等待子进程结束,守护进程直接结束

    import time
    from multiprocessing import Process
    def func1():
        count = 1
        while True:
            time.sleep(0.5)
            print(count*'*')
            count += 1
    def func2():
        print('func2 start')
        time.sleep(5)
        print('func2 end')
    if __name__ == '__main__':
        p = Process(target=func1)
        p.daemon = True # 在start之前,将p设置为守护进程
        p.start()
        p2 = Process(target=func2)
        p2.start()
        time.sleep(3)
        print('主进程')
    
    #结果:只打印了5次*
    func2 start
    *
    **
    ***
    ****
    *****
    主进程
    func2 end

    四、Lock 互斥锁

    Lock是一个类,在使用的时候要进行导入,和Process一样

    Lock的作用:在异步的情况下,多个进程又可能修改同一份资源,就给这个修改的过程加上锁。

    加锁降低了程序的效率,让原来能够同时执行的代码变成顺序执行,但是保证了数据的安全。

    例如:火车票抢票

    import json
    import time
    from multiprocessing import Process,Lock
    def search(person):
        with open('ticket') as f:
            dic = json.load(f)
        time.sleep(0.2)  # 模拟网络延迟
        print('%s进行余票查询:'%person,dic['count'])
    
    def get_ticket(person):
        with open('ticket') as f:
            dic = json.load(f)
        time.sleep(0.2)
        if dic['count'] > 0:
            dic['count'] -= 1
            print('%s买到票了'%person)
            time.sleep(0.2)
            with open('ticket','w') as f:
                json.dump(dic,f)
        else:
            print('%s没买到票'%person)
    def main(person,lock):
        search(person)
        lock.acquire()
        get_ticket(person)
        lock.release()
    if __name__ == '__main__':
        lock = Lock()
        for i in range(10):
            p = Process(target=main,args=(i,lock))
            p.start()
    
    #结果是:
    1进行余票查询: 6
    2进行余票查询: 6
    3进行余票查询: 6
    7进行余票查询: 6
    0进行余票查询: 6
    6进行余票查询: 6
    4进行余票查询: 6
    9进行余票查询: 6
    5进行余票查询: 6
    8进行余票查询: 6
    1买到票了
    2买到票了
    3买到票了
    7买到票了
    0买到票了
    6买到票了
    4没买到票
    9没买到票
    5没买到票
    8没买到票

    五、Semaphore信号量

    信号量的作用:互斥锁Lock只允许一个线程更改数据,而信号量Semaphore同时允许一定数量的线程更改数据

    信号量是计数器+锁实现的

    例如:ktv允许同一时间4个人唱歌

    import random
    import time
    from multiprocessing import Process,Semaphore
    def ktv(person,sem):
        sem.acquire()
        print('33[31m%s走进ktv33[0m'%person)
        time.sleep(random.randint(1,5))
        print('33[32m%s走出ktv33[0m'%person)
        sem.release()
    if __name__ == '__main__':
        sem = Semaphore(4) # 同时允许4个人做
        for i in range(10):
            p = Process(target=ktv,args=(i,sem))
            p.start()

    六、Event 事件

    Event的作用:用于主线程控制其他线程的执行,Event主要提供了3个方法:set、wait、clear

    Event的处理机制:全局定义了一个'Flag',如果flag的值为false。那么当程序执行event.wait方法时就会阻塞,如果flag值为True,那么遇到event.wait方法时就不会阻塞

    set():将’Flag‘设置为True

    clear():将flag设置为false

    is_set():判断flag当前属性是否为true

    著名的例子:红绿灯

    import time
    import random
    from multiprocessing import Process,Event
    def traffic_light(e):
        print('33[31m红灯亮33[0m')
        while True:
            if e.is_set():  # if True,本来是绿灯亮,变为红灯,将flag设为false
                time.sleep(2)
                print('33[31m红灯亮33[0m')
                e.clear()
            else:
                time.sleep(2)
                print('33[32m绿灯亮33[0m')
                e.set()
    def car(e,i):
        if not e.is_set(): # 红灯
            print('car%s在等待'%i)
            e.wait()  # 阻塞
        print('car%s通过了'%i)
    if __name__ == '__main__':
        e = Event()
        p = Process(target=traffic_light,args=(e,))
        p.daemon = True  # 将p设为守护进程,主进程代码执行完毕就结束
        p.start()
        p_lst = []
        for i in range(20):
            time.sleep(random.randrange(0,3,2))
            p = Process(target=car,args=(e,i))
            p.start()
            p_lst.append(p)
        for p in p_lst:
            p.join()  # 当子进程结束时,主进程才开始执行
  • 相关阅读:
    2019-09-29-阿里三面
    【Layui】在前端提交表单时验证密码是否正确
    【Mivik 的字符串公开赛A】大佬语录(广义后缀自动机)
    【2020ICPC南京J】Just Another Game of Stones(Nim博弈+吉老师线段树)
    【HDU-6291/2018CCPC女生赛E】对称数(散列+树上主席树)
    【计蒜客42547/2019ICPC徐州H】Yuuki and a problem(MEX性质+树套树)
    【HDU-6230/2017CCPC哈尔滨A】Palindrome(式子转换+马拉车+主席树)
    【HDU-6223/2017ICPC沈阳G】Infinite Fraction Path(后缀数组+超级快读)
    【HDU-5785】Interesting(回文串的性质+回文自动机+map空间优化)
    【CF-1452E】Two Editorials (贪心)
  • 原文地址:https://www.cnblogs.com/tian-tian/p/9677528.html
Copyright © 2020-2023  润新知