在python中管道和分叉

时间:2013-10-30 19:16:30

标签: python fork piping

我正在尝试在python中编写一个程序,它通过父函数将2个整数写入管道,然后通过子函数读取相同的整数。然后应该将子函数打印出两者的乘积。

问题是,当我运行它时,它会像它应该的那样等待5秒但是然后返回值441而不是2。

希望有人可以帮助弄清楚如何修复此代码:)

import os,time

def child(pipein):
    while True:
        num1 = int(os.read(pipein,32))
        num2 = int(os.read(pipein,32))
        r=(num1)*(num2)
        print(r)
        os._exit(0)

def parent():
    pipein,pipeout = os.pipe()
    x=5
    if os.fork()==0:
        child(pipein)
    else:
        while True:
            num1=str(2)
            num2=str(1)
            line=os.write(pipeout,num1.encode())
            line=os.write(pipeout,num2.encode())
            time.sleep(x)   

parent()

2 个答案:

答案 0 :(得分:0)

直接的问题是你的孩子有一个无限循环,在做任何事情之前,一遍又一遍地阅读num1(或者更确切地说,阅读它两次,然后永远阻止第三个永远不会来的输入)。

通过将更多代码移动到while循环来修复此问题,如下所示:

def child(pipein):
    while True:
        num1 = int(os.read(pipein,32))
        num2 = int(os.read(pipein,32))
        r=(num1)*(num2)
        print(r)

你也可以删除os._exit(0),因为无论如何你永远都不会去。{/ p>


您的下一个问题是您的编码和解码步骤不匹配。只要你的sys.getdefaultencoding()是ASCII的严格超集(或者,实际上,只要它的数字与ASCII数字匹配),你就可以逃脱这一点,但你真的不应该默默地依赖它。


接下来,os.read(pipein,32)可以为您提供单次写入的结果,或者它可以为您提供最多32个单独写入组合在一起的结果。 write(最高为PIPE_BUF)保证是原子的这一事实对你没有帮助 - 它只是意味着你不能以写入的前半部分而不是后半部分结束。

所以,很有可能,你会在21中获得num1,然后在5秒后获得21中的另一个num2,而不是打印{ {1}}每5秒钟,您将每10秒打印一次2。但即使这样也无法保证。

管道,如TCP套接字,是byte streams, not message streams。这意味着您需要构建某种协议。


这里有两个非常明显的选择。

首先,由于您已经读取了(最多)32字节的固定记录大小,为什么不写一个完全32字节的固定记录大小?只需将441行更改为生成正好为32个字符的字符串的字符串,该字符串将在已有效的任何编码中编码为32个字节,并将解析为适当值的单个整数。像这样:

str

或者,每条记录可以是一对以空格分隔的数字,记录可以用换行符分隔。解析这一点很简单。特别是因为你没有使用非阻塞管道或任何东西,所以你可以在它们周围放置一个文件对象并使它变得容易。

答案 1 :(得分:-1)

这就是我要做的;

from __future__ import print_function  #(1)
import os  #(2)
import sys
import time


def child(pipein):  # (3)
    num1 = int(os.read(pipein, 32))  # (6)
    num2 = int(os.read(pipein, 32))
    r = num1 * num2
    print("r = {}".format(r))
    print("Child says bye.") 
    sys.stdout.flush()  # (4)
    os._exit(0)  # (5)


def parent():
    pipein, pipeout = os.pipe()
    x = 1
    if os.fork() == 0:
        print("Launching child")
        child(pipein)
    else:  # (7)
        print("In parent")
        num1 = str(2)  # (8)
        num2 = str(1)
        os.write(pipeout, num1)
        os.write(pipeout, num2)
        print("Parent goes to sleep")
        time.sleep(x)
        print("Parent says bye.")


if __name__ == '__main__':
    parent()
  1. 这是使print() 函数在Python 2.x中工作所必需的
  2. 样式:每个都应在单独的行中导入
  3. 如果您在第一次迭代后转到exit(),则无需循环
  4. 否则打印件可能不会显示。
  5. 样式:在函数后使用两个空行。
  6. 样式:在逗号后面使用空格,除非它在一行的末尾。
  7. 删除while循环,否则您将处于无限循环中。
  8. 样式:在运营商周围使用空格。
  9. 通过这些修改,我得到以下输出;

    In parent
    Launching child
    Parent goes to sleep
    r = 2
    Child says bye.
    Parent says bye.
    

    如果要使用多个进程,使用multiprocessing模块通常会更好。它包含进程和进程池的对象,以及队列和管道等通信对象。队列是先进先出,并且它们是同步的;因此,如果您放入两个项目,则可以阅读两个项目。