`
Ydoing
  • 浏览: 106117 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Python进程间通信之匿名管道

 
阅读更多

匿名管道

管道是一个单向通道,有点类似共享内存缓存.管道有两端,包括输入端和输出端.对于一个进程的而言,它只能看到管道一端,即要么是输入端要么是输出端.

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]"
<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

    Python进程通信之匿名管道实例讲解

    匿名管道是一种简单但基础的进程间通信(IPC)方式,它提供了一个单向的数据通道。在Python中,我们可以使用`os`模块提供的`pipe()`函数创建匿名管道。`os.pipe()`会返回两个文件描述符,一个用于读取(rpipe),另...

    详解Python进程间通信之命名管道

    **Python进程间通信详解:命名管道** 在多进程编程中,进程间通信(Inter-Process Communication, IPC)是一项核心技术,使得不同进程可以共享数据、协调工作。在Python中,有多种实现进程间通信的方式,其中之一...

    进程间通信的四种方式

    进程间通信中剪切板的使用 创建和使用剪切板 -----------------------------------------------Parent--Child--------------------------------------------------- 匿名管道只能在父子进程之间进行通信 匿名...

    jc.rar_进程的管道通信

    总的来说,“jc.rar_进程的管道通信”这一主题为我们提供了一个深入学习进程间通信机制的机会,通过理解并实践管道通信,我们可以更好地掌握多进程协同工作的方法,这对于编写高效、可靠的多线程和分布式系统至关...

    Python中使用PIPE操作Linux管道

    在*nix系统中,管道是最古老、最基本的一种进程间通信(IPC)方式。 管道是一种半双工的通信机制,意味着数据只能在一个方向上流动,即只能从一端写入,另一端读取。数据一旦被读取,就会从管道中消失,因此管道中不...

    posix ipc python库源码

    4. **命名管道(Named Pipes/FIFOs)**:命名管道是另一种简单的进程间通信方式,提供单向通信。`NamedPipe`类提供了创建、读写管道的方法,如`mkfifo`用于创建管道,`open`用于打开管道,`read`和`write`用于数据...

    Python并发编程以及系统常用模块

    进程是程序的一次执行,它具有自己的内存空间和数据栈,不同进程间的信息不能直接共享,必须通过进程间通信(IPC)来交换数据。线程则是运行在同一个进程内的执行流,它们共享同一片数据空间,能够更容易地共享信息...

    python面试宝典汇总.zip

    同时,进程间通信(IPC)如管道、消息队列、共享内存也是面试热点。 9. **文件操作**:熟练掌握读写文件,包括文本文件和二进制文件,以及文件的打开模式。了解文件对象的方法,如read、write、seek、tell等。 10....

    阿里巴巴 2019 Python 面试题(内部资料)招聘高级开发、测试开发工程师

    多进程则是每个进程都有独立的内存空间,进程间通信需要通过IPC机制实现。 - **资源管理**:多线程由于共享内存空间,可以更容易地共享资源,但这也意味着需要更多的同步机制来保护共享资源。多进程则需要使用其他...

    2019千峰Python超详细入门教程(百度云盘分享).docx

    - **进程间通信**: - Pipe管道的使用。 - Queue队列的使用。 - 线程锁的概念和使用。 - **线程调度**: - 线程调度的基本原理。 - 定时器线程的创建。 #### 第15章 网络编程 - **网络编程基础**: - TCP/IP...

    命名管道.zip

    命名管道在Linux操作系统中是一种非常重要的进程间通信(IPC,Inter-Process Communication)机制,它允许不同的进程之间共享数据流。这种通信方式是半双工的,也就是说,数据只能在一个方向上传输,而且数据一旦被...

    ipc.zip_IPC

    标题中的"ipc.zip_IPC"表明这是一个与IPC(Inter-Process Communication,进程间通信)相关的压缩包文件。IPC是计算机程序之间进行通信的一种机制,它允许不同进程共享数据、协调工作,是多进程系统中不可或缺的部分...

    Linux系统教学中关于命名管道文件的解析.pdf

    命名管道(Named Pipe)是Linux操作系统中一种进程间通信(IPC,Inter-Process Communication)的方式,它允许不同的进程之间共享数据。与无名管道(Anonymous Pipe)相比,命名管道最大的特点在于它具有名字,可以...

    kdbus的简介

    《KDBUS:现代世界的进程间通信解决方案》 在当今高度互联的世界中,进程间通信(IPC)成为了软件系统设计中的关键环节。Greg Kroah-Hartman在其关于KDBUS的介绍PPT中,深入探讨了这一主题,揭示了KDBUS如何为现代...

    调用外部程序

    6. **命名管道和匿名管道**:在Windows系统中,提供了一种简单的进程间通信方式。 在提供的压缩包文件中,"www.pudn.com.txt"可能包含了如何在特定环境下调用外部程序的示例代码或教程,而"使用Fastcopy"可能是一个...

    管道

    与匿名管道不同,命名管道可以在不同的进程之间或者跨多个会话提供通信,因为它们有自己的文件系统路径。创建命名管道可以使用`mkfifo`命令,如下所示: ```bash mkfifo my_pipe ``` 然后,两个或更多进程可以打开...

    ruby 程序设计

    - **进程间通信**:通过管道、文件等手段实现进程间的通信。 #### 十一、基本I/O操作 ##### §11.1 使用Kernel模块处理I/O操作 - **读写文件**:通过`File.open`打开文件,`puts`写入内容等。 ##### §11.2 文件...

    Ruby经典学习教程(口碑不错)

    - 进程间的通信较为复杂,通常使用管道或共享内存等方式。 #### 十一、基本I/O操作 **11.1 使用Kernel模块处理I/O操作** - `Kernel`模块提供了读写文件的基本方法。 **11.2 文件处理** - 包括打开、关闭、读取...

Global site tag (gtag.js) - Google Analytics