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 相关文章推荐
关于你不想知道的所有Python3 unicode特性
Nov 28 Python
matplotlib在python上绘制3D散点图实例详解
Dec 09 Python
Sublime开发python程序的示例代码
Jan 24 Python
python批量修改图片大小的方法
Jul 24 Python
Python 文本文件内容批量抽取实例
Dec 10 Python
Python 使用folium绘制leaflet地图的实现方法
Jul 05 Python
python 插入日期数据到Oracle实例
Mar 02 Python
pytorch 中的重要模块化接口nn.Module的使用
Apr 02 Python
Pytorch损失函数nn.NLLLoss2d()用法说明
Jul 07 Python
如何使用python写截屏小工具
Sep 29 Python
python字符串常规操作大全
May 02 Python
Python包argparse模块常用方法
Jun 04 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中$_SERVER的详细参数与说明
2008/07/29 PHP
ajax完美实现两个网页 分页功能的实例代码
2013/04/16 PHP
探讨如何在php168_cms中提取验证码
2013/06/08 PHP
Javascript 陷阱 window全局对象
2008/11/26 Javascript
Javascript 强制类型转换函数
2009/05/17 Javascript
动态显示可输入的字数提示还可以输入的字数
2014/04/01 Javascript
IE8中使用javascript动态加载CSS的解决方法
2014/06/17 Javascript
javascript学习笔记(四)function函数部分
2014/09/30 Javascript
介绍JavaScript的一个微型模版
2015/06/24 Javascript
nodejs导出excel的方法
2015/06/30 NodeJs
JavaScript获得url查询参数的方法
2015/07/02 Javascript
JavaScript实现简单Tip提示框效果
2016/04/20 Javascript
JS实现的幻灯片切换显示效果
2016/09/07 Javascript
Nodejs进阶:如何将图片转成datauri嵌入到网页中去实例
2016/11/21 NodeJs
原生js调用json方法总结
2018/02/22 Javascript
ES6 系列之 Generator 的自动执行的方法示例
2018/10/19 Javascript
vue实现登录页面的验证码以及验证过程解析(面向新手)
2019/08/02 Javascript
[58:23]LGD vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python使用自带的ConfigParser模块读写ini配置文件
2016/06/26 Python
Python中关于Sequence切片的下标问题详解
2017/06/15 Python
python opencv设置摄像头分辨率以及各个参数的方法
2018/04/02 Python
Python3爬虫之自动查询天气并实现语音播报
2019/02/21 Python
python TK库简单应用(实时显示子进程输出)
2019/10/29 Python
用python写爬虫简单吗
2020/07/28 Python
使用Python+Appuim 清理微信的方法
2021/01/26 Python
世界上最大的街头服饰网站:Karmaloop
2017/02/04 全球购物
中东奢侈品市场:Coveti
2019/05/12 全球购物
服装机修工岗位职责
2013/12/26 职场文书
社区交通安全实施方案
2014/03/22 职场文书
交通志愿者活动总结
2014/06/27 职场文书
创先争优活动心得体会
2014/09/04 职场文书
2014年大学教师工作总结
2014/12/02 职场文书
初一年级组工作总结
2015/08/12 职场文书
自愿离婚协议书范本2016
2016/03/18 职场文书
2016年第16个全民国防教育日宣传活动总结
2016/04/05 职场文书
Python通过loop.run_in_executor执行同步代码 同步变为异步
2022/04/11 Python