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下线程之间的共享和释放示例
May 04 Python
python使用smtplib模块通过gmail实现邮件发送的方法
May 08 Python
Python基于回溯法子集树模板解决0-1背包问题实例
Sep 02 Python
python用户管理系统的实例讲解
Dec 23 Python
更改Python的pip install 默认安装依赖路径方法详解
Oct 27 Python
Python 中Django验证码功能的实现代码
Jun 20 Python
详解python实现小波变换的一个简单例子
Jul 18 Python
Python实现报警信息实时发送至邮箱功能(实例代码)
Nov 11 Python
python 实现在无序数组中找到中位数方法
Mar 03 Python
python3.4中清屏的处理方法
Jul 06 Python
python3中确保枚举值代码分析
Dec 02 Python
python中使用 unittest.TestCase单元测试的用例详解
Aug 30 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截取指定图片大小的方法
2014/12/10 PHP
jscript之Open an Excel Spreadsheet
2007/06/13 Javascript
$()JS小技巧
2007/07/21 Javascript
解决jquery .ajax 在IE下卡死问题的解决方法
2009/10/26 Javascript
javascript 鼠标拖动图标技术
2010/02/07 Javascript
jQuery中:input选择器用法实例
2015/01/03 Javascript
基于Javascript实现倒计时功能
2016/02/22 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
2016/03/19 Javascript
jQuery EasyUI Pagination实现分页的常用方法
2016/05/21 Javascript
ES6 Promise对象概念与用法分析
2017/04/01 Javascript
详解组件库的webpack构建速度优化
2018/06/18 Javascript
微信小程序实现左右列表联动
2020/05/19 Javascript
vue路由权限校验功能的实现代码
2020/06/07 Javascript
Antd中单个DatePicker限定时间输入范围操作
2020/10/29 Javascript
[06:44]2014DOTA2国际邀请赛-钥匙体育馆开战 开幕式振奋人心
2014/07/19 DOTA
python入门教程之识别验证码
2017/03/04 Python
Python Flask-web表单使用详解
2017/11/18 Python
在Pandas中处理NaN值的方法
2019/06/25 Python
Kali Linux安装ipython2 和 ipython3的方法
2019/07/11 Python
Python基于模块Paramiko实现SSHv2协议
2020/04/28 Python
Python基于gevent实现文件字符串查找器
2020/08/11 Python
Python命令行参数argv和argparse该如何使用
2021/02/08 Python
HTML5中原生的右键菜单创建方法
2016/06/28 HTML / CSS
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
介绍一下SOA和SOA的基本特征
2016/02/24 面试题
士力架广告词
2014/03/20 职场文书
财产公证书格式
2014/04/10 职场文书
留守儿童工作方案
2014/06/02 职场文书
财务会计实训报告
2014/11/05 职场文书
继承权公证书范本
2015/01/23 职场文书
党员个人承诺书
2015/04/27 职场文书
土木工程生产实习心得体会
2016/01/22 职场文书
实习报告范文之电话客服岗位
2019/07/26 职场文书
为什么RedisCluster设计成16384个槽
2021/09/25 Redis
Python使用Beautiful Soup(BS4)库解析HTML和XML
2022/06/05 Python
MySQL提升大量数据查询效率的优化神器
2022/07/07 MySQL