Python进程通信之匿名管道实例讲解


Posted in Python onApril 11, 2015

匿名管道

管道是一个单向通道,有点类似共享内存缓存.管道有两端,包括输入端和输出端.对于一个进程的而言,它只能看到管道一端,即要么是输入端要么是输出端.

os.pipe()返回2个文件描述符(r, w),表示可读的和可写的.示例代码如下:

#!/usr/bin/python

import time

import os
def child(wpipe):

    print('hello from child', os.getpid())

    while True:

        msg = 'how are you\n'.encode()

        os.write(wpipe, msg)

        time.sleep(1)
def parent():

    rpipe, wpipe = os.pipe()

    pid = os.fork()

    if pid == 0:

        child(wpipe)

        assert False, 'fork child process error!'

    else:

        os.close(wpipe)

        print('hello from parent', os.getpid(), pid)

        fobj = os.fdopen(rpipe, 'r')

        while True:

            recv = os.read(rpipe, 32)

            print recv
parent()

输出如下:
('hello from parent', 5053, 5054)

('hello from child', 5054)

how are you
how are you
how are you
how are you

我们也可以改进代码,不用os.read()从管道中读取二进制字节,而是从文件对象中读取字符串.这时需要用到os.fdopen()把底层的文件描述符(管道)包装成文件对象,然后再用文件对象中的readline()方法读取.这里请注意文件对象的readline()方法总是读取有换行符'\n'的一行,而且连换行符也读取出来.还有一点要改进的地方是,把父进程和子进程的管道中不用的一端关闭掉.

#!/usr/bin/python

import time

import os
def child(wpipe):

    print('hello from child', os.getpid())

    while True:

        msg = 'how are you\n'.encode()

        os.write(wpipe, msg)

        time.sleep(1)
def parent():

    rpipe, wpipe = os.pipe()

    pid = os.fork()

    if pid == 0:

        os.close(rpipe)

        child(wpipe)

        assert False, 'fork child process error!'

    else:

        os.close(wpipe)

        print('hello from parent', os.getpid(), pid)

        fobj = os.fdopen(rpipe, 'r')

        while True:

            recv = fobj.readline()[:-1]

            print recv
parent()

输出如下:

('hello from parent', 5108, 5109)

('hello from child', 5109)

how are you

how are you

how are you

如果要与子进程进行双向通信,只有一个pipe管道是不够的,需要2个pipe管道才行.以下示例在父进程新建了2个管道,然后再fork子进程.os.dup2()实现输出和输入的重定向.spawn功能类似于subprocess.Popen(),既能发送消息给子进程,由能从子子进程获取返回数据.
#!/usr/bin/python

#coding=utf-8

import os, sys
def spawn(prog, *args):

    stdinFd = sys.stdin.fileno()

    stdoutFd = sys.stdout.fileno()
    parentStdin, childStdout = os.pipe()

    childStdin, parentStdout= os.pipe()
    pid = os.fork()

    if pid:

        os.close(childStdin)

        os.close(childStdout)

        os.dup2(parentStdin, stdinFd)#输入流绑定到管道,将输入重定向到管道一端parentStdin

        os.dup2(parentStdout, stdoutFd)#输出流绑定到管道,发送到子进程childStdin

    else:

        os.close(parentStdin)

        os.close(parentStdout)

        os.dup2(childStdin, stdinFd)#输入流绑定到管道

        os.dup2(childStdout, stdoutFd)

        args = (prog, ) + args

        os.execvp(prog, args)

        assert False, 'execvp failed!'
if __name__ == '__main__':

    mypid = os.getpid()

    spawn('python', 'pipetest.py', 'spam')
    print 'Hello 1 from parent', mypid #打印到输出流parentStdout, 经管道发送到子进程childStdin

    sys.stdout.flush()

    reply = raw_input()

    sys.stderr.write('Parent got: "%s"\n' % reply)#stderr没有绑定到管道上
    print 'Hello 2 from parent', mypid

    sys.stdout.flush()

    reply = sys.stdin.readline()#另外一种方式获得子进程返回信息

    sys.stderr.write('Parent got: "%s"\n' % reply[:-1])

pipetest.py代码如下:

#coding=utf-8

import os, time, sys
mypid = os.getpid()

parentpid = os.getppid()

sys.stderr.write('child %d of %d got arg: "%s"\n' %(mypid, parentpid, sys.argv[1]))
for i in range(2):

    time.sleep(3)

    recv = raw_input()#从管道获取数据,来源于父经常stdout

    time.sleep(3)

    send = 'Child %d got: [%s]' % (mypid, recv)

    print(send)#stdout绑定到管道上,发送到父进程stdin

    sys.stdout.flush()

输出:

child 7265 of 7264 got arg: "spam"

Parent got: "Child 7265 got: [Hello 1 from parent 7264]"

Parent got: "Child 7265 got: [Hello 2 from parent 7264]"
Python 相关文章推荐
Python笔记(叁)继续学习
Oct 24 Python
python计算时间差的方法
May 20 Python
python中将\\uxxxx转换为Unicode字符串的方法
Sep 06 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 Python
Python datetime和unix时间戳之间相互转换的讲解
Apr 01 Python
python利用tkinter实现屏保
Jul 30 Python
利用OpenCV和Python实现查找图片差异
Dec 19 Python
Django def clean()函数对表单中的数据进行验证操作
Jul 09 Python
社区版pycharm创建django项目的方法(pycharm的newproject左侧没有项目选项)
Sep 23 Python
python归并排序算法过程实例讲解
Nov 04 Python
python 三种方法实现对Excel表格的读写
Nov 19 Python
matplotlib之多边形选区(PolygonSelector)的使用
Feb 24 Python
Python multiprocessing模块中的Pipe管道使用实例
Apr 11 #Python
Python httplib模块使用实例
Apr 11 #Python
初步探究Python程序的执行原理
Apr 11 #Python
Python与shell的3种交互方式介绍
Apr 11 #Python
Python函数参数类型*、**的区别
Apr 11 #Python
Python中的多重装饰器
Apr 11 #Python
Python中的各种装饰器详解
Apr 11 #Python
You might like
php类的扩展和继承用法实例
2015/06/20 PHP
PHP编程入门的基本语法知识点总结
2016/01/26 PHP
淘宝搜索框效果实现分析
2011/03/05 Javascript
javascript中window.event事件用法详解
2012/12/11 Javascript
javascript中定义私有方法说明(private method)
2014/01/27 Javascript
调用innerHTML之后onclick失效问题的解决方法
2014/01/28 Javascript
Window.Open如何在同一个标签页打开
2014/06/20 Javascript
分享20款美化网站的 jQuery Lightbox 灯箱插件
2014/10/10 Javascript
自己封装的常用javascript函数分享
2015/01/07 Javascript
如何改进javascript代码的性能
2015/04/02 Javascript
iframe中使用jquery进行查找的方法【案例分析】
2016/06/17 Javascript
第七篇Bootstrap表单布局实例代码详解(三种表单布局)
2016/06/21 Javascript
jQuery 全选 全部选 反选 实现代码
2016/08/17 Javascript
利用yarn实现一个webpack+react种子
2016/10/25 Javascript
VUE中v-model和v-for指令详解
2017/06/23 Javascript
手把手教你搭建ES6的开发运行环境
2017/07/11 Javascript
原生JS实现自定义滚动条效果
2020/10/27 Javascript
Angular5中调用第三方js插件的方法
2018/02/26 Javascript
详解vue路由篇(动态路由、路由嵌套)
2019/01/27 Javascript
vue.js购物车添加商品组件的方法
2019/09/17 Javascript
在vscode 中设置 vue模板内容的方法
2020/09/02 Javascript
[02:40]DOTA2英雄基础教程 巨牙海民
2013/12/23 DOTA
[00:32]2018DOTA2亚洲邀请赛出场——LGD
2018/04/04 DOTA
python 3.7.0 下pillow安装方法
2018/08/27 Python
对Python 多线程统计所有csv文件的行数方法详解
2019/02/12 Python
Django在pycharm下修改默认启动端口的方法
2019/07/26 Python
Selenium基于PIL实现拼接滚动截图
2020/04/10 Python
LocalStorage记住用户和密码功能
2017/07/24 HTML / CSS
俄罗斯名牌服装网上商店:UNIQUE FABRIC
2019/07/25 全球购物
linux面试题参考答案(10)
2016/10/26 面试题
工伤事故赔偿协议书
2014/04/15 职场文书
小学生评语大全
2014/04/18 职场文书
《画家乡》教学反思
2014/04/22 职场文书
经贸日语专业自荐信
2014/09/02 职场文书
2019学校请假条格式及范文
2019/06/25 职场文书
职场领导同事生日简短祝福语
2019/08/06 职场文书