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基于select实现的socket服务器
Apr 13 Python
纯用NumPy实现神经网络的示例代码
Oct 24 Python
Python数据集切分实例
Dec 08 Python
python 动态生成变量名以及动态获取变量的变量名方法
Jan 20 Python
完美解决Python matplotlib绘图时汉字显示不正常的问题
Jan 29 Python
从0开始的Python学习016异常
Apr 08 Python
Python tkinter实现图片标注功能(完整代码)
Dec 08 Python
Python3 pywin32模块安装的详细步骤
May 26 Python
python Socket网络编程实现C/S模式和P2P
Jun 22 Python
python 将列表里的字典元素合并为一个字典实例
Sep 01 Python
python BeautifulSoup库的安装与使用
Dec 17 Python
Python安装使用Scrapy框架
Apr 12 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字符比较函数similar_text、strnatcmp与strcasecmp用法分析
2014/11/18 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
PHP 出现 http500 错误的解决方法
2021/03/09 PHP
JS中Iframe之间传值及子页面与父页面应用
2013/03/11 Javascript
javascript实现yield的方法
2013/11/06 Javascript
javaScript如何处理从java后台返回的list
2014/04/24 Javascript
一个不错的字符串转码解码函数(自写)
2014/07/31 Javascript
轻松创建nodejs服务器(1):一个简单nodejs服务器例子
2014/12/18 NodeJs
js+html5实现canvas绘制简单矩形的方法
2015/06/05 Javascript
javascript实现标签切换代码示例
2016/05/22 Javascript
基于jQuery实现中英文切换导航条效果
2016/09/18 Javascript
BootStrap入门教程(二)之固定的内置样式
2016/09/19 Javascript
纯JS实现图片验证码功能并兼容IE6-8(推荐)
2017/04/19 Javascript
ubuntu编译nodejs所需的软件并安装
2017/09/12 NodeJs
Angular5升级RxJS到5.5.3报错:EmptyError: no elements in sequence的解决方法
2018/04/09 Javascript
nodejs高大上的部署方式(PM2)
2018/09/11 NodeJs
基于Vue SEO的四种方案(小结)
2019/07/01 Javascript
Vue-cli4 配置 element-ui 按需引入操作
2020/09/11 Javascript
从运行效率与开发效率比较Python和C++
2018/12/14 Python
python虚拟环境完美部署教程
2019/08/06 Python
用python的turtle模块实现给女票画个小心心
2019/11/23 Python
python matplotlib模块基本图形绘制方法小结【直线,曲线,直方图,饼图等】
2020/04/26 Python
Python中的__init__作用是什么
2020/06/09 Python
django rest framework 自定义返回方式
2020/07/12 Python
Python爬虫过程解析之多线程获取小米应用商店数据
2020/11/14 Python
详解Python GUI编程之PyQt5入门到实战
2020/12/10 Python
CSS3实现超酷的黑猫警长首页
2016/04/26 HTML / CSS
详解canvas多边形(蜘蛛图)的画法示例
2018/01/29 HTML / CSS
牵手50新加坡:专为黄金岁月的单身人士而设的交友网站
2020/08/16 全球购物
销售经理工作职责
2014/02/03 职场文书
诉前财产保全担保书
2014/05/20 职场文书
金融专业毕业生自荐信
2014/06/26 职场文书
小学新教师个人总结
2015/02/05 职场文书
聘任协议书(挂靠)
2015/09/21 职场文书
《灰雀》教学反思
2016/02/19 职场文书
使用python绘制横竖条形图
2022/04/21 Python