• 我的Python成长之路---第八天---Python基础(25)---2016年3月5日(晴)


    多进程 multiprocessing模块

    multiprocessing模块提供了一个Process类来代表一个进程对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #!/usr/bin/env python3
    # coding:utf-8
    '''
    Created on: 2016年3月5日
     
    @author: 张晓宇
     
    Email: 61411916@qq.com
     
    Version: 1.0
     
    Description: 多进程演示程序
     
    Help:
    '''
    from multiprocessing import Process
    import os
     
     
    def run_proc(name):
        # 子进程要执行的函数
        print('Run child process %s (%s)...' % (name, os.getpid())) # os.getpid()表示获得当前进程的pid
     
    if __name__=='__main__':
        print('Parent process %s.' % os.getpid()) # 打印父进程的pid
        p = Process(target=run_proc, args=('test',)) # 创建进程对象,参数结构和多线程一样
        print('Child process will start.')
        p.start() # 启动子进程
        p.join() # 阻塞等待子进程执行完毕
        print('Child process end.')

    进程间通信

    Queue

    不同进程间内存是不共享,所以多进程不能像多线程一样通过全局变量(当然全局变量也是不提倡的),所以只能通过队列,多进程模块也自带一个队列Queue,使用方法和threading里的queue差不多

    Pipe

    管道,可以理解为两个进程之间的一个桥梁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #!/usr/bin/env python3
    # coding:utf-8
    '''
    Created on: 2016年3月5日
     
    @author: 张晓宇
     
    Email: 61411916@qq.com
     
    Version: 1.0
     
    Description: 管道演示程序
     
    Help:
    '''
    from multiprocessing import Process, Pipe
     
    def f(conn):
        conn.send([42, None, 'hello']) # 网管道里传递数据
        conn.close()
     
    if __name__ == '__main__':
        parent_conn, child_conn = Pipe() # 一个是父进程的管道对象,一个是子进程的对象,自己成往里面send,父进程对象recv,有点像socket
        p = Process(target=f, args=(child_conn,)) # 把管道对象作为参数传递给子进程
        p.start()
        print(parent_conn.recv())   # 接收管道里的数据并打印出来
        p.join()

    执行结果

    1
    [42, None, 'hello']

    有人会说既然可以往子进程要执行的而函数传递参数,直接通过这个参数取子进程传递过来的数据就好了,比如可以用列表等可变数据类型(字符串和数值型等不可变类型的数据,想都不要想,统一进程都做不到)为啥还用管道或队列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #!/usr/bin/env python3
    # coding:utf-8
    '''
    Created on: 2016年3月5日
     
    @author: 张晓宇
     
    Email: 61411916@qq.com
     
    Version: 1.0
     
    Description: 管道演示程序
     
    Help:
    '''
    from multiprocessing import Process, Pipe
     
    def f(conn, strinfo):
        conn.send([42, None, 'hello']) # 网管道里传递数据
        conn.close() # 关闭管道
        strinfo.append('child')
     
    if __name__ == '__main__':
        parent_conn, child_conn = Pipe() # 一个是父进程的管道对象,一个是子进程的对象,自己成往里面send,父进程对象recv,有点像socket
        strinfo = ['parent']
        p = Process(target=f, args=(child_conn, strinfo)) # 把管道对象作为参数传递给子进程
        p.start()
        print(parent_conn.recv())   # 接收管道里的数据并打印出来
        print(strinfo)
        p.join()

    执行结果

    1
    2
    [42, None, 'hello']
    ['parent']

    从执行结果中可以看出来,strinfo的值并没有变化,那是因为,进程启动的时候重新划分了内存空间,等于将strinfo在子进程中copy了一份,已经和父进程中的strinfo没有半毛钱关系了所以要有管道队列等

    进程池

    进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程, 如果进程池序列没有可提供的进程,那么就会等待,知道有可用进程为止

    Pool模块有两种常用的启动进程的方法

    apply和apply_assync,从字面上理解是apply_assync是异步的,其实就是apply_assync支持把一个函数作为参数传递进去,当进程函数执行完的时候可以通过return一个值,这个值,会自动作为参数传递个传递进来的函数,并执行该函数,我们称之为回调(callback)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #!/usr/bin/env python
    # coding:utf-8
    '''
    Created on: 2016年3月5日
     
    @author: 张晓宇
     
    Email: 61411916@qq.com
     
    Version: 1.0
     
    Description: 进程池演示程序
     
    Help:
    '''
    from  multiprocessing import Pool, freeze_support
    import time
     
    def Foo(i):
        '''
        子进程执行的函数
        :param i:
        :return:
        '''
        time.sleep(2)
        return i+100
     
    def Bar(arg):
        '''
        子进程回调函数
        :param arg:
        :return:
        '''
        print('-->exec done:',arg)
     
    if __name__ == '__main__': # 这个在windows环境中绝对不能省略否则会报错
        freeze_support()
        pool = Pool(5) # 创建进程池对象
     
        for i in range(10):
            pool.apply_async(func=Foo, args=(i,), callback=Bar)
            # pool.apply(func=Foo, args=(i,))
        print('end')
        pool.close()
        pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

    执行结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    end
    -->exec done: 100
    -->exec done: 101
    -->exec done: 102
    -->exec done: 103
    -->exec done: 104
    -->exec done: 105
    -->exec done: 106
    -->exec done: 107
    -->exec done: 108
    -->exec done: 109
  • 相关阅读:
    chrome、firefox、IE中input输入光标位置错位解决方案
    IE兼容opacity
    Linux下redis5的安装及伪分布式集群搭建
    Linux文件编辑命令详细整理
    saltstack
    redis集群
    系统调优
    centos7 telnet 登录升级ssh
    keepalive简单高可用 ha
    docker
  • 原文地址:https://www.cnblogs.com/zhangxiaxuan/p/5502423.html
Copyright © 2020-2023  润新知