美文网首页
Python并行编程(七):多进程的基本使用和与多线程的差异

Python并行编程(七):多进程的基本使用和与多线程的差异

作者: 若数 | 来源:发表于2019-04-14 19:34 被阅读0次

    进程

    由于GIL的存在,Python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在Python中大部分情况需要使用多进程。Python提供了非常好用的多进程模块multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个模块,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了ProcessLockQueuePipe等组件。

    multiprocessing包是Python中的多进程模块。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(),run(), join()的方法。此外multiprocessing模块中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading模块中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。
    当然多进程的定义方式也和多线程类似,即两种方式:

    目标函数实例化定义新的进程:

    # 导入多进程模块
    from multiprocessing import Process
    
    # os.getpid() 获取当前进程的id
    import os
    
    def run_proc(name):
        print('{} child process is {}'.format(name, os.getpid()))
    
    if __name__ == '__main__':
        print("Parent process is {}".format(os.getpid()))
        p = Process(target=run_proc, args=('test', ))
        print('child process will start...')
        p.start()
        p.join()
    
        print('child process end.')
    

    运行截图如下:


    运行截图

    继承类来定义新的进程

    from multiprocessing import Process
    import os
    
    
    class RunProc(Process):
        def __init__(self, name):
            Process.__init__(self)
    
            self.name = name
    
        def run(self):
            print('{} child process is {}'.format(self.name, os.getpid()))
    
    
    if __name__ == "__main__":
        print("Parent process is {}".format(os.getpid()))
        p = RunProc('test')
        print('child process will start...')
        p.start()
        p.join()
    
        print('child process end.')
    

    运行结果如下:


    运行截图

    我们可以看见,多进程的使用方式和多线程几乎一样,比如以下:
    Process([group [, target [, name [, args [, kwargs]]]]])

    • group: 线程组,目前还没有实现,库引用中提示必须是None;
    • target: 要执行的方法;
    • name: 进程名;
    • args/kwargs: 要传入方法的参数。

    实例方法:

    • is_alive():返回进程是否在运行。
    • join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
    • start():进程准备就绪,等待CPU调度
    • run():strat()调用run方法,如果实例进程时未制定传入targetstart执行默认的· run()方法。
    • terminate():不管任务是否完成,立即停止工作进程

    属性:

    • daemon:和线程的setDeamon功能一样
    • exitcode(进程在运行时为None、如果为–N,表示被信号N结束)
    • name:进程名字。
    • pid:进程号。

    进程的独立性:

    和线程不一样的是,进程之间相互独立,我们可以从全局变量的修改窥见一些:

    from multiprocessing import Process
    
    # 测试数据
    ex_list = 'Hello World'
    
    # 修改数据进程
    def revise_data():
        global ex_list
    
        # 修改全局变量
        ex_list = ex_list + ' with write revise_data process.'
        print('wirte result:', ex_list)
    
    # 查看数据进程
    def view_data():
        print(ex_list)
    
    if __name__ == "__main__":
        process_revise = Process(target=revise_data)
        process_view = Process(target=view_data)
    
        process_revise.start()
    
        # 主进程等待写入进程执行完成以后代码 再继续往下执行
        process_revise.join()
    
        process_view.start()
        process_view.join()
    
        print("process end.")
    

    运行截图如下:


    运行结果

    我们定义了两个进程,分别用来修改全局变量和查看修改后的数据,我们看见虽然修改的进程已经成功修改了变量,但是在查看进程中全局变量仍然是原来的值,即进程之间是不共享全局变量的,即创建子进程其实是对主进程进行拷贝,进程之间相互独立,访问的全局变量不是同一个,所以进程之间不共享全局变量。

    相关文章

      网友评论

          本文标题:Python并行编程(七):多进程的基本使用和与多线程的差异

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