美文网首页
多进程笔记:

多进程笔记:

作者: 97833632c0c7 | 来源:发表于2018-06-01 13:03 被阅读0次

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

    1. 在Python中,可以通过`os.fork()`创建子进程,但是这种方式只能在`linux`和`unix`以及`mac`下面使用,不能跨平台,所以一般不推荐使用这种方式。

    2. 使用`multiprocessing`模块也可以创建多进程,并且这种方式在写起来更加简单,并且支持跨平台。所以一般推荐使用`multiprocessing`的方式来写多进程的代码。

    ### `multiprocessing`的基本用法:

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

    ```python

    from multiprocessing import Process

    import time

    def zhiliao():

        print('zhiliao process')

    if __name__ == '__main__':

        # 开启一个子进程

        p = Process(target=zhiliao)

        p.start()

        while True:

            print('main process')

            time.sleep(1)

    ```

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

    ### 获取进程号:

    1. 通过`os.getpid()`可以获取到当前这个进程的id。

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

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

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

    ### `join`方法:

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

    ```python

    def zhiliao():

        for x in range(5):

            print('子进程:%s' % x)

            time.sleep(1)

    if __name__ == '__main__':

        p = Process(target=zhiliao)

        p.start()

        print('主进程')

        # join方法的时候,就相当于主进程会阻塞在这个地方

        # 直到这个子进程执行完毕以后才会执行父进程后的代码

        p.join(3)

        print('所有子进程都执行完毕')

    ```

    ### 使用类的方式创建子进程:

    1. 使用`Process`作为父类,重新自定义一个类。

    2. 在自定义的类中,重写父类的`run`方法,这个是必须的。其他方法,就按照你平时如何写就可以了。

    3. 使用自定义的进程类创建子进程的时候,不需要传`target`参数。

    ```python

    class MyProcess(Process):

        def run(self):

            print('子进程的id:%s' % os.getpid())

            print('父进程的id:%s' % os.getppid())

            for x in range(5):

                print('子进程:%s' % x)

    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`相当于是并联的方式执行(同一时刻可以执行多个任务)。`apply`相当于是串联的方式执行(同一时刻只能执行一个任务,并且只能等待前面的任务执行完后才能执行后面的任务)。

    ```python

    from multiprocessing import Process,Pool

    import os

    import time

    def worker(num):

        for x in range(5):

            print('num:%s,pid:%s' % (num, os.getpid()))

            time.sleep(1)

    if __name__ == '__main__':

        # 这个池子中同一时刻最多只能有3个进程

        pool = Pool(3)

        for x in range(10):

            pool.apply_async(worker,(x,))

        # 关闭进程池,不能再添加新进程了

        pool.close()

        # 主进程把子进程添加到进程池中后,不会等待进程池中其他的子进程都执行完毕后再退出,

        # 而是当主进程的代码执行完毕后会立刻退出,因此如果这个地方没有join,那么子进程

        # 将得不到执行

        pool.join()

    ```

    ### 进程间数据不共享:

    在程序中创建了子进程,子进程会完全copy一份主进程的环境,包括变量、函数、类等。

    所以在子进程中使用变量、函数等的时候,其实是使用的是子进程中的那一份。跟主进程没有任何关系。

    ### `Queue`消息队列:

    1. Queue(n):初始化一个消息队列,并指定这个队列中最多能够容纳多少条消息。

    2. put(obj,[block[,timeout]]):推入一条消息到这个队列中。默认是阻塞的,也就是说如果这个消息队列中已经满了,那么会会一直等待,将这个消息添加到消息队列中。timeout可以指定这个阻塞最长的时间,如果超过这个时间还是满的,就会抛出异常。

    3. put_nowait() :非阻塞的推入一条消息,如果这个队列已经满了,那么会立马抛出异常。其实这个方法等价于`put(block=False)`。

    4. qsize():获取这个消息队列消息的数量。

    5. full():判断这个消息队列是满否了。

    6. empty():判断这个消息队列是否空了。

    7. get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,block默认为True。如果设置block为False,那么如果没值,会立马抛出异常。timeout指定如果多久没有获取到值后会抛出异常。他获取值的方式是以先进先出的方式获取的。不要被队列两个字误解了。

    ### 使用`Queue`做进程间通信:

    1. 给`Process`进程做通信:直接使用`Queue`的对象作为进程的参数就可以了。

    2. 给`Pool`进程做通信,应该使用`multiprocessing.Manager().Queue()`对象来做通信,这个对象的使用方法跟`multiprocessing.Queue()`是一样的。

    相关文章

      网友评论

          本文标题:多进程笔记:

          本文链接:https://www.haomeiwen.com/subject/dhbmjftx.html