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 25 Python
Python函数参数类型*、**的区别
Apr 11 Python
Python编程scoketServer实现多线程同步实例代码
Jan 29 Python
解决Python print 输出文本显示 gbk 编码错误问题
Jul 13 Python
Python requests模块实例用法
Feb 11 Python
django多文件上传,form提交,多对多外键保存的实例
Aug 06 Python
Python对接支付宝支付自实现功能
Oct 10 Python
PyQt5连接MySQL及QMYSQL driver not loaded错误解决
Apr 29 Python
Python实现常见的几种加密算法(MD5,SHA-1,HMAC,DES/AES,RSA和ECC)
May 09 Python
Python读取Excel一列并计算所有对象出现次数的方法
Sep 04 Python
详解Django的MVT设计模式
Apr 29 Python
Django模型层实现多表关系创建和多表操作
Jul 21 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执行速度全攻略
2006/10/09 PHP
php+xml结合Ajax实现点赞功能完整实例
2015/01/30 PHP
js可突破windows弹退效果代码
2008/08/09 Javascript
jquery插件制作 手风琴Panel效果实现
2012/08/17 Javascript
javascript unicode与GBK2312(中文)编码转换方法
2013/11/14 Javascript
深入理解Javascript作用域与变量提升
2013/12/09 Javascript
js判断url是否有效的两种方法
2014/03/04 Javascript
获取中文字符串的实际长度代码
2014/06/05 Javascript
jQuery中:nth-child选择器用法实例
2014/12/31 Javascript
jQuery实现自定义事件的方法
2015/04/17 Javascript
JavaScript实现点击按钮复制指定区域文本(推荐)
2016/11/25 Javascript
js数字舍入误差以及解决方法(必看篇)
2017/02/28 Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
2017/09/26 Javascript
vue项目中api接口管理总结
2018/04/20 Javascript
jQuery实现的淡入淡出图片轮播效果示例
2018/08/29 jQuery
小程序使用watch监听数据变化的方法详解
2019/09/20 Javascript
高效jQuery选择器的5个技巧实例分析
2019/11/26 jQuery
vue多个元素的样式选择器问题
2019/11/29 Javascript
vue下axios拦截器token刷新机制的实例代码
2020/01/17 Javascript
书单|人生苦短,你还不用python!
2017/12/29 Python
Python面向对象之接口、抽象类与多态详解
2018/08/27 Python
python os模块简单应用示例
2019/05/23 Python
PyQtGraph在pyqt中的应用及安装过程
2019/08/04 Python
python3实现带多张图片、附件的邮件发送
2019/08/10 Python
Django框架 信号调度原理解析
2019/09/04 Python
超实用的 30 段 Python 案例
2019/10/10 Python
Python绘制二维曲线的日常应用详解
2019/12/04 Python
Python中Qslider控件实操详解
2021/02/20 Python
广州品高软件.net笔面试题目
2012/04/18 面试题
硕士研究生自我鉴定范文
2013/12/27 职场文书
社区学习十八大感想
2014/01/22 职场文书
园林技术个人的自我评价
2014/02/15 职场文书
自强自立美德少年事迹材料
2014/08/16 职场文书
小学家长意见怎么写
2015/06/03 职场文书
升学宴学生致辞
2015/09/29 职场文书
2019大学毕业晚会主持词
2019/06/21 职场文书