python多进程中实现进程间数据传递和通信

技术文档网 2021-05-06

进程与线程一个不同点在于,线程之可以共享一块内存空间,而进程的内存空间是互相独立的,进程之间要传递数据需要依靠“中间人”,而Queue类能够提供这个功能

下面这个程序使用的是普通queue模块实例化的队列,通过父进程向子进程传递了一个普通队列,并在run函数中向队列添加了一个列表元素,用于检验父进程能否get到这个元素.

#Downtiser
import multiprocessing, queue

def run(q):
    q.put(['a', 1, 'bcd'])


if __name__ == '__main__':
    q1 = queue.Queue()  #实例化普通队列
    p = multiprocessing.Process(target=run, args=(q1,))
    p.start()
    p.join()
    print(q1.get())

结果抛出了一个异常>>>TypeError: can't pickle _thread.lock objects

于是使用多进程Queue做同样操作

#Downtiser
import multiprocessing, queue

def run(q):
    q.put(['a', 1, 'bcd'])

if __name__ == '__main__':
    q1 = multiprocessing.Queue()  #实例化多进程队列
    p = multiprocessing.Process(target=run, args=(q1,))
    p.start()
    p.join()
    print(q1.get())

此时主进程能正常get到队列中的元素>>>['a', 1, 'bcd']
难道是多进程队列实现了不同进程之间共享数据? 于是修改程序,打印队列本身,如果是共享的话,在主进程和子进程里打印的队列应该拥有同一块内存地址。程序修改如下:

#Downtiser
import multiprocessing, queue

def run(q):
    print('这是子进程的队列>>>',q)
    q.put(['a', 1, 'bcd'])


if __name__ == '__main__':
    q1 = multiprocessing.Queue()  #实例化多进程队列
    print('这是主进程的队列>>>',q1)
    p = multiprocessing.Process(target=run, args=(q1,))
    p.start()
    p.join()
    print(q1.get())

得结果如下:

这是主进程的队列>>> <multiprocessing.queues.Queue object at 0x04A3EC50>
这是子进程的队列>>> <multiprocessing.queues.Queue object at 0x04CEDC30>
['a', 1, 'bcd']

可以发现两个队列的内存地址并不同,所以两个进程实际上并没有共享一个队列,而是子进程复制了一份主进程的队列。查阅资料了解到,多进程队列实际上是将原队列先传递到一个"中间人"处,通过pickle序列化,反序列化,中间人将队列信息传递到另一个进程处,另一个进程将队列修改后,再传递给中间人,其他进程调用时就会发现队列被修改了,表面上达到了共享数据的效果

多进程队列实现了进程间数据传递,而多进程管道,可实现进程间通信,类似于socket

代码实现如下

#Downtiser
import multiprocessing
def run(conn):
    conn.send("这是子进程")
    print(conn.recv())

if __name__ == '__main__':
    conn_parent, conn_children = multiprocessing.Pipe()  #创建管道实例,建立两个连接,类似于socket
    p = multiprocessing.Process(target=run, args=(conn_children,)) #创建子进程,并将管道子端传入
    p.start()
    print(conn_parent.recv())
    conn_parent.send('我是父进程')
    p.join()

结果:

这是子进程
我是父进程

Manager实现数据共享

#Downtiser
import multiprocessing, os

def run(dic, lis):
    dic['pid'] = os.getpid()
    lis.append(os.getpid())
    print('---子进程>>>', hex(id(dic)), hex(id(lis)))
    print(lis)


if __name__ == '__main__':
    with multiprocessing.Manager() as manager: #生成Manager实例,该实例可用于实现进程间的数据共享
        dic = manager.dict()  #通过manager生成一个可共享的字典
        lis = manager.list()  #同上
        print('---主进程>>>',hex(id(dic)), hex(id(lis)))  #16进制返回变量的内存地址
        p_list = []
        for i in range(10):
            p = multiprocessing.Process(target=run, args=(dic, lis))
            p_list.append(p)
            p.start()
        for p in p_list:
            p.join()
        print(dic)

结果:

---主进程>>> 0x58f89d0 0x58130f0
---子进程>>> 0x5491af0 0x5494890
[3520]
---子进程>>> 0x58a1510 0x58a4730
[3520, 9748]
---子进程>>> 0x5281ad0 0x5284870
[3520, 9748, 6560]
---子进程>>> 0x5771ad0 0x5774870
[3520, 9748, 6560, 15732]
---子进程>>> 0x54a1ab0 0x54a4850
[3520, 9748, 6560, 15732, 13140]
---子进程>>> 0x5731b10 0x57348b0
[3520, 9748, 6560, 15732, 13140, 13136]
---子进程>>> 0x5911af0 0x5914890
[3520, 9748, 6560, 15732, 13140, 13136, 16176]
---子进程>>> 0x5b21ad0 0x5b24870
[3520, 9748, 6560, 15732, 13140, 13136, 16176, 11624]
---子进程>>> 0x5801b10 0x58048b0
[3520, 9748, 6560, 15732, 13140, 13136, 16176, 11624, 13228]
---子进程>>> 0x5aa1af0 0x5aa4890
[3520, 9748, 6560, 15732, 13140, 13136, 16176, 11624, 13228, 4716]
{'pid': 4716

用Manager还可支持其他多种类型的数据,如元组,队列,信号量,进程锁等

相关文章

  1. Django基本命令

    Django基本命令 打开linux终端直接在终端中输入以下命令即可。 新建一个django project 命令:django-admin.py startproject project-nam

  2. 17个新手常见Python运行时错误

    17个新手常见Python运行时错误 当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂。这里列出了常见的的一些让你程序 crash 的运行时错误。 当初学 Python

  3. Python+SQLite真的有用吗?

    SQLite是个很简单的数据库,一个文件就可以搞定,存储上千万行的数据也没问题,图形界面程序有很多,管理很方便,用Python可以编程操作,也很简单,一切都似乎很完美。 我导入了几千万行的数据进SQL

  4. os各种各样的操作系统接口

    这个模块提供了一种使用操作系统相关功能的移动方式。如果您只想读取或写入一个文件,请查看open(),如果您想要操作路径,请参见操作os.path模块,如果您想要读取命令行上所有文件中的所有行,请参阅f

  5. 通过webpy和nginx-with-fastcgi搭建web.py

    这一节讲解的是如何使用Nginx和FastCGI搭建Web.py应用 环境依赖的软件包 Nginx 0.8.* or 0.7.* (需要包含fastcgi和rewrite模块)。 Webpy 0.3

随机推荐

  1. Django基本命令

    Django基本命令 打开linux终端直接在终端中输入以下命令即可。 新建一个django project 命令:django-admin.py startproject project-nam

  2. 17个新手常见Python运行时错误

    17个新手常见Python运行时错误 当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂。这里列出了常见的的一些让你程序 crash 的运行时错误。 当初学 Python

  3. Python+SQLite真的有用吗?

    SQLite是个很简单的数据库,一个文件就可以搞定,存储上千万行的数据也没问题,图形界面程序有很多,管理很方便,用Python可以编程操作,也很简单,一切都似乎很完美。 我导入了几千万行的数据进SQL

  4. os各种各样的操作系统接口

    这个模块提供了一种使用操作系统相关功能的移动方式。如果您只想读取或写入一个文件,请查看open(),如果您想要操作路径,请参见操作os.path模块,如果您想要读取命令行上所有文件中的所有行,请参阅f

  5. 通过webpy和nginx-with-fastcgi搭建web.py

    这一节讲解的是如何使用Nginx和FastCGI搭建Web.py应用 环境依赖的软件包 Nginx 0.8.* or 0.7.* (需要包含fastcgi和rewrite模块)。 Webpy 0.3