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以环状形式组合排列图片并输出的方法
Mar 17 Python
深入解析Python中的线程同步方法
Jun 14 Python
Python如何import文件夹下的文件(实现方法)
Jan 24 Python
基于Python的关键字监控及告警
Jul 06 Python
Python实现的寻找前5个默尼森数算法示例
Mar 25 Python
解决python通过cx_Oracle模块连接Oracle乱码的问题
Oct 18 Python
浅析Python+OpenCV使用摄像头追踪人脸面部血液变化实现脉搏评估
Oct 17 Python
Pycharm debug调试时带参数过程解析
Feb 03 Python
使用Python画了一棵圣诞树的实例代码
Nov 27 Python
利用python制作拼图小游戏的全过程
Dec 04 Python
python中time.ctime()实例用法
Feb 03 Python
jupyter notebook保存文件默认路径更改方法汇总(亲测可以)
Jun 09 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网站基础优化方法小结
2008/09/29 PHP
php中将汉字转换成拼音的函数代码
2012/09/08 PHP
解析link_mysql的php版
2013/06/30 PHP
linux系统下php安装mbstring扩展的二种方法
2014/01/20 PHP
php实现的常见排序算法汇总
2014/09/08 PHP
PHP 等比例缩放图片详解及实例代码
2016/09/18 PHP
Yii框架用户登录session丢失问题解决方法
2017/01/07 PHP
javascript延时加载之defer测试
2012/12/28 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
基于Jquery和CSS3制作数字时钟附源码下载(CSS3篇)
2015/11/24 Javascript
javascript定义类和类的实现实例详解
2015/12/01 Javascript
js阻止浏览器默认行为的简单实例
2016/05/15 Javascript
移动端使用localStorage缓存Js和css文的方法(web开发)
2016/09/20 Javascript
jQuery实现边框动态效果的实例代码
2016/09/23 Javascript
NodeJS中的MongoDB快速入门详细教程
2016/11/11 NodeJs
jquery二级目录选中当前页的css样式
2016/12/08 Javascript
angular分页指令操作
2017/01/09 Javascript
在 Angular2 中实现自定义校验指令(确认密码)的方法
2017/01/23 Javascript
浅谈vue.js中v-for循环渲染
2017/07/26 Javascript
浅谈ECMAScript6新特性之let、const
2017/08/02 Javascript
NodeJS有难度的面试题(能答对几个)
2019/10/09 NodeJs
Python实现生成随机日期字符串的方法示例
2017/12/25 Python
python获取网页中所有图片并筛选指定分辨率的方法
2018/03/31 Python
浅谈配置OpenCV3 + Python3的简易方法(macOS)
2018/04/02 Python
python读取和保存视频文件
2018/04/16 Python
Python决策树之基于信息增益的特征选择示例
2018/06/25 Python
Django 迁移、操作数据库的方法
2019/08/02 Python
python等差数列求和公式前 100 项的和实例
2020/02/25 Python
python标准库OS模块函数列表与实例全解
2020/03/10 Python
Python爬虫实例——爬取美团美食数据
2020/07/15 Python
详解Python的爬虫框架 Scrapy
2020/08/03 Python
软件测试英文面试题
2012/10/14 面试题
检察院对照“四风”认真查找问题落实整改措施
2014/09/26 职场文书
群众路线查摆问题整改措施
2014/10/10 职场文书
HR必备:超全面的薪酬待遇管理方案!
2019/07/12 职场文书
Python四款GUI图形界面库介绍
2022/06/05 Python