• python-----多进程笔记


    多进程笔记:

    在Python中多进程的创建方式对比:

    1.在Python中,可以通过os.fork()创建子进程,但是这种方式智能在'linux'和'unix'以及'mac'下面使用,不能跨平台,所以一般不推荐使用这种方式。
    2.使用'multiprocessing'模块也可以创建多进程,并且这种方式在写起来更加简单,并且支持跨平台,
    所以一般推荐使用'multiprocessing'的方式来写多进程的代码。

    'multiprocessing'的基本用法:

    'multiprocessing'这个模块下面有一个'Process'的类,使用这个类可以创建一个多进程,使用方式如下:

    from multiprocessing import Process
    import os
    
    def demo():
        print('我是子进程--->')
        print('子进程进程号是%s'%(os.getpid()))
        print('父进程进程号是%s'%(os.getppid()))
    
    if __name__ == '__main__':
        p = Process(target=demo)
        p.start()
        print('主进程的进程号是%s'%(os.getpid()))
    

    需要注意一点的是,如果在'windows'操作系统下,
    所有和进程创建相关的代码都必须放在'if name == 'main''下面,否则会报错。

    获取进程号:

    1.通过'os.getpid()'可以获取到当前这个进程的id
    2.通过'os.getppid()'可以获取到当前这个进程的父进程的id

    父进程会等待所有子进程执行完毕后再退出:

    如果在父进程中执行完所有代码后,还有子进程在执行,那么父进程会等待子进程执行完所有代码后再退出。

    'join'方法:

    'join'方法可以让你的主进程阻塞,直到这个子进程执行完毕以后才会执行主进程后面的代码。

    from multiprocessing import Process
    import os
    import time
    
    def demo():
        for i in range(5):
            print('子进程')
            time.sleep(1)
    
    if __name__ == '__main__':
        p = Process(target=demo)
        p.start()
        print('主进程')
    
        p.join() # join方法的时候,就相当于主进程会阻塞在这个地方,直到这个子进程执行完毕以后才会执行父进程后的代码
        print('执行完毕')
    

    适用于类的方式创建子进程

    1.使用'Process'作为父类,重新自定义一个类。
    2.在自定义的类中,重写父类的'run'方法,这个是必须的,其他方法,就按照你平时如何写就可以了。
    3.使用自定义的进程类创建子进程的时候,不需要传'target'参数。

    from multiprocessing import Process
    import os
    class MyProcess(Process):
        def run(self):
            print('子进程的id:%s' % os.getpid())
            print('父进程的id:%s' % os.getppid())
            for i in range(5):
                print('子进程:%s'%i)
    
    if __name__ == '__main__':
        p = MyProcess()
        p.start()
        print('父进程的id:%s'%os.getpid())
        print('子进程开始了')
        p.join()
        print('子进程结束了')
    

    进程池:

    1.'multiprocessing'中的'Pool'可以实现一个容器,来管理子进程。
    2.使用进程池有什么好处,进程池可以控制同一时刻,最多只能有多少个进程在运行。
    3.主进程不会等待进程池中的子进程都执行完毕以后再退出,二十如果父进程代码执行完毕以后,就会将整个程序都退出,
    所有我们在写进程池的时候,应该使用'pool.join()'来保证进程池中所有的子进程都能够执行完成。
    4.'apply_async'相当于是并联的方式执行(同一时刻只能执行一个任务,并且只能等待前面的任务执行完后,才能执行后面的任务)

    from multiprocessing import Pool
    import os
    import time
    def demo(num):
        for x in range(5):
            print('子进程id:%s ,值:%s'% (os.getpid(),num))
            time.sleep(2)
    if __name__ == '__main__':
        # 这个池子中同一时刻最多只能有3个进程
        pool = Pool(2)
        for x in range(10):
            pool.apply_async(demo,args=(x,))
        # 关闭进程池,不能再添加新进程了
        pool.close()
        # 主进程把子进程添加到进程池中后,不会等待进程池中其他的子进程都执行完毕后再退出,
        # 而是当主进程的代码执行完毕后悔立刻退出,因此如果这个地方没有join,那么子进程将得不到执行。
        pool.join()
    

    进程间数据不共享:

    在程序中创建了子进程,子进程会完全copy一份主进程的环境,包括变量、函数、类等。
    所以在子进程中使用变量、函数等的时候,其实是使用的是子进程中的那一份,跟主进程没有任何关系。

    from  multiprocessing import Process
    
    AGE = 1
    
    def hello():
        print('hello')
    
    def greet(names):
        global AGE
        AGE += 1
        names.append('ketang')
        print('=====子进程代码=====')
        print('AGE的值:%d, AGE的id:%s' % (AGE,id(AGE)))
        print('names:%s' % names)
        print(id(hello))
        print('=====子进程代码=====')
    
    if __name__ == '__main__':
        names = ['demo']
        p = Process(target=greet,args=(names,))
        p.start()
        p.join()
        print('=====父进程代码=====')
        print('AGE的值:%d, AGE的id:%s' % (AGE,id(AGE)))
        print('names:%s' % names)
        print(id(hello))
        print('=====父进程代码=====')
    

    Queue消息队列:

    1. Queue(n):初始化一个消息队列,并指定这个队列中最多能够容纳多少条消息。
    2. put(obj,[block,[timeout]]):推入一条消息到这个队列中。默认是阻塞的,也就是说如果这个消息队列中已经满了,
      那么会一直等待,将这个消息添加到消息队列中。timeout可以指定这个阻塞最长时间,如果超过这个时间还是满的,就会抛出异常。
    3. put_nowait():非阻塞的推入一条消息,如果这个队列已经满了,那么会立马抛出异常。
    4. qsize():获取这个消息队列消息的数量。
    5. full():判断这个消息队列是否满了。
    6. empty():判断这个消息队列是否空了。
    7. get([block,[timeout]]):获取队列中的一条消息,然后将其从队列中移除,block默认为True。如果设置block为False,
      那么如果没值,会立马抛出异常。timeout指定如果多久没有获取到值后会抛出异常。
    from multiprocessing import Queue
    
    # Queue可以指定maxsize的值
    # 以后这个队列中就只能装maxsize个值
    # 如果不指定,那么就是为-1
    # -1 意味着可以装任意多个消息,直到你的内存满了
    q = Queue(3)
    
    # put方法,可以传递任意数据类型的消息
    q.put('m1')
    q.put('m2')
    q.put('m3')
    # qsize: 获取这个消息队列中总共的消息数量
    print('qsize:%s' % q.qsize())
    # full, 如果消息队列满了,那么会返回True,否则返回False
    print(q.full())
    # empty:如果消息队列为空,那么会返回True,否则返回False
    print(q.empty())
    
    # put方法默认是阻塞的方式
    # 如果消息队列已经满了,那么会阻塞在这个地方,直到这个消息队列没有满为止
    # block参数:可以设置为False,如果为False,那么意味着不会阻塞,如果消息队列满了,那么会立马抛出一个异常
    # timeout参数:指定阻塞的最长时间。如果超过了这个时间就不再阻塞,而是抛出一个异常。
    # q.put('m4',block=True,timeout=2)
    # put_nowait:其实等价于q.put(obj,block=False)
    # q.put_nowait('m4')
    # print('finished')
    
    # get方法:获取到的是第一个添加进去的值。
    # get方法:除了获取这个值外,还会把这个值从消息队列中删除掉
    # block参数:默认是等于True,即以阻塞的方式获取值,如果这个队列中没有任何消息,那么会阻塞到这个地方。如果block=False,那么如果队列中没有值,就会立即抛出异常。
    # timeout参数:指定阻塞的最长时间,如果超过了这个时间就不再阻塞,而是抛出一个异常
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get(block=True,timeout=2))
    

    使用Queue做进程间通信:

    1. Process进程做通信:直接使用Queue的对象座位进程的参数就可以了。
    2. Pool进程做通信,应该使用multiprocessing.Manager().Queue()对象来做通信,
      这个对象的使用方法跟multiprocessing.Queue()是一样的。
    from multiprocessing import Process,Queue
    import os
    
    def write(q):
        for x in ['m1','m2','m3']:
            q.put(x)
            print('子进程%s已经存放了消息:%s' % (os.getpid(),x))
    
    def read(q):
        while True:
            try:
                msg = q.get(block=False)
                print('子进程%s已经读取了消息:%s' % (os.getpid(),msg))
            except:
                print('所有消息都已经取出来了')
                break
    
    if __name__ == '__main__':
        q = Queue()
        pw = Process(target=write,args=(q,))
        pr = Process(target=read,args=(q,))
    
        pw.start()
        pr.start()
    
        pw.join()
    
    from multiprocessing import Process,Queue,Pool,Manager
    import os
    
    def write(q):
        for x in ['m1','m2','m3']:
            q.put(x)
            print('子进程%s已经存放了消息:%s' % (os.getpid(),x))
    
    def read(q):
        while True:
            try:
                msg = q.get(block=False)
                print('子进程%s已经读取了消息:%s' % (os.getpid(),msg))
            except:
                print('所有消息都已经取出来了')
                break
    
    if __name__ == '__main__':
        q = Manager().Queue()
        pool = Pool(2)
        pool.apply(func=write,args=(q,))
        pool.apply(func=read,args=(q,))
    
    
  • 相关阅读:
    Zabbix监控系统系列之二 : 初始化配置
    docker中的zabbix 配置钉钉机器人
    sqldbx 绿色小巧的数据库查询管理工具
    Windows 10 自建Anki 私有云服务器
    Sqlserver内存管理:限制最大占用内存
    tfs强制撤销其他工作区挂起更改,删除工作区
    easyui的一些文档
    IIS下日志分析
    zookeeper-client
    Windbg程序调试系列-索引篇(转)
  • 原文地址:https://www.cnblogs.com/xiaodai0/p/11217954.html
Copyright © 2020-2023  润新知