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 Web框架Tornado运行和部署
Oct 19 Python
详解Python多线程
Nov 14 Python
python 容器总结整理
Apr 04 Python
python 实现将txt文件多行合并为一行并将中间的空格去掉方法
Dec 20 Python
利用anaconda保证64位和32位的python共存
Mar 09 Python
远程部署工具Fabric详解(支持Python3)
Jul 04 Python
Tensorflow: 从checkpoint文件中读取tensor方式
Feb 10 Python
对Matlab中共轭、转置和共轭装置的区别说明
May 11 Python
Python使用paramiko连接远程服务器执行Shell命令的实现
Mar 04 Python
Django Paginator分页器的使用示例
Jun 23 Python
基于Python编写简易版的天天跑酷游戏的示例代码
Mar 23 Python
Python Pandas解析读写 CSV 文件
Apr 11 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中jsonp的跨域实例
2013/06/21 PHP
国外十大最流行的PHP框架排名
2013/07/04 PHP
php使用curl发送json格式数据实例
2013/12/17 PHP
如何通过Linux命令行使用和运行PHP脚本
2015/07/29 PHP
PHP基于自定义类随机生成姓名的方法示例
2017/08/05 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
2017/11/14 PHP
js CSS操作方法集合
2008/10/31 Javascript
一个简单的弹性返回顶部JS代码实现介绍
2013/06/09 Javascript
JS组件系列之Bootstrap Icon图标选择组件
2016/01/28 Javascript
Javascript设计模式之观察者模式(推荐)
2016/03/29 Javascript
onclick和onblur冲突问题的快速解决方法
2016/04/28 Javascript
原生js编写焦点图效果
2016/12/08 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
Vue数据驱动模拟实现2
2017/01/11 Javascript
从零开始学习Node.js系列教程五:服务器监听方法示例
2017/04/13 Javascript
JavaScript面向对象程序设计创建对象的方法分析
2018/08/13 Javascript
Vue 中文本内容超出规定行数后展开收起的处理的实现方法
2019/04/28 Javascript
解决antd 表单设置默认值initialValue后验证失效的问题
2020/11/02 Javascript
[02:59]DOTA2完美大师赛主赛事第三日精彩集锦
2017/11/25 DOTA
[02:23]2018DOTA2亚洲邀请赛趣味视频——反应测试
2018/04/04 DOTA
在Windows服务器下用Apache和mod_wsgi配置Python应用的教程
2015/05/06 Python
在Apache服务器上同时运行多个Django程序的方法
2015/07/22 Python
python调用百度地图WEB服务API获取地点对应坐标值
2019/01/16 Python
python程序 创建多线程过程详解
2019/09/23 Python
python中的selenium安装的步骤(浏览器自动化测试框架)
2020/03/17 Python
Django+Celery实现动态配置定时任务的方法示例
2020/05/26 Python
利用CSS3的border-radius绘制太极及爱心图案示例
2016/05/17 HTML / CSS
英国家庭珠宝商:T. H. Baker
2018/02/08 全球购物
Nike瑞典官方网站:Nike.com (SE)
2018/11/26 全球购物
日本著名的服饰鞋帽综合类购物网站:MAGASEEK
2019/01/09 全球购物
驾驶员岗位职责
2014/01/29 职场文书
本科毕业生求职自荐信
2014/02/03 职场文书
新闻学专业大学生职业生涯规划范文
2014/03/02 职场文书
企业安全生产月活动总结
2014/07/05 职场文书
nginx 多个location转发任意请求或访问静态资源文件的实现
2021/03/31 Servers
Python使用random模块实现掷骰子游戏的示例代码
2021/04/29 Python