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实现划词翻译
Apr 23 Python
python计算书页码的统计数字问题实例
Sep 26 Python
Python中list初始化方法示例
Sep 18 Python
python urllib爬取百度云连接的实例代码
Jun 19 Python
python交互式图形编程实例(二)
Nov 17 Python
PyCharm代码回滚,恢复历史版本的解决方法
Oct 22 Python
Python格式化输出字符串方法小结【%与format】
Oct 29 Python
解决pycharm的Python console不能调试当前程序的问题
Jan 20 Python
Python实现的多进程拷贝文件并显示百分比功能示例
Apr 09 Python
pycharm无法导入本地模块的解决方式
Feb 12 Python
Python3中PyQt5简单实现文件打开及保存
Jun 10 Python
Pytest中skip skipif跳过用例详解
Jun 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按指定键值对二维数组进行排序的方法
2015/12/22 PHP
php开发时容易忘记的一些技术细节
2016/02/03 PHP
PHP实现添加购物车功能
2017/03/06 PHP
PHP实现微信对账单处理
2018/10/01 PHP
Laravel基础-关于引入公共文件的两种方式
2019/10/18 PHP
jQuery 白痴级入门教程
2009/11/11 Javascript
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
Javascript核心读书有感之表达式和运算符
2015/02/11 Javascript
readonly和disabled属性的区别
2015/07/26 Javascript
js事件处理程序跨浏览器解决方案
2016/03/27 Javascript
Angular中$broadcast和$emit的使用方法详解
2017/05/22 Javascript
Angular实现的简单定时器功能示例
2017/12/28 Javascript
vuex 的简单使用
2018/03/22 Javascript
利用npm 安装删除模块的方法
2018/05/15 Javascript
JS构造一个html文本内容成文件流形式发送到后台
2018/07/31 Javascript
JavaScript数据结构之栈实例用法
2019/01/18 Javascript
js实现消灭星星(web简易版)
2020/03/24 Javascript
vue router-link 默认a标签去除下划线的实现
2020/11/06 Javascript
html中创建并调用vue组件的几种方法汇总
2020/11/17 Javascript
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
零基础写python爬虫之神器正则表达式
2014/11/06 Python
python使用PIL模块获取图片像素点的方法
2019/01/08 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
解决PyCharm不运行脚本,而是运行单元测试的问题
2019/01/17 Python
pytorch下大型数据集(大型图片)的导入方式
2020/01/08 Python
tensorflow实现在函数中用tf.Print输出中间值
2020/01/21 Python
css3实现平移效果(transfrom:translate)的示例
2020/11/13 HTML / CSS
韩都衣舍天猫官方旗舰店:天猫女装销售总冠军
2017/10/10 全球购物
计算机通信工程专业毕业生推荐信
2013/12/24 职场文书
学生感冒英文请假条
2014/02/04 职场文书
目标责任书格式
2014/07/28 职场文书
解除劳动关系协议书范文
2014/09/11 职场文书
债务追讨律师函
2015/06/24 职场文书
深入解析MySQL索引数据结构
2021/10/16 MySQL
解决 Redis 秒杀超卖场景的高并发
2022/04/12 Redis
ipad隐藏软件app图标方法
2022/04/19 数码科技