2013-10-30 39 views
-5

我試圖編寫一個程序在Python中通過父函數將2個整數寫入管道,然後通過子函數讀取那些相同的整數。那麼孩子的功能應該打印出兩者的產品。在Python中管道和分叉

的問題是,當我運行它,它會等待話,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

您的新版本在第一對「read」之後退出,因此打印第一個值後會永遠阻止。 – abarnert

回答

-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. 風格:使用操作員周圍的空間。

通過這些修改,我得到以下輸出;

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

如果你想使用多個進程,它通常是一個更好的主意使用multiprocessing模塊。它具有進程和進程池的對象,以及隊列和管道等通信對象。隊列是先進先出的,它們是同步的;所以如果你放入兩件物品,你可以閱讀兩件物品。

+0

如果你想在Python 2中完成這項工作,你絕對不想在'str'上調用'encode'。 – abarnert

+0

更重要的是,這實際上並沒有解決問題,並引入了一個_new_問題(父母可以在孩子仍在跑步時退出)。如果第一個「閱讀」碰巧抓住了整個「21」(如通常在大多數平臺上),那麼孩子將永遠不會打印任何東西。 – abarnert

+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),因爲你永遠不會無論如何去實現它。


您的下一個問題是您的編碼和解碼步驟不匹配。只要你的sys.getdefaultencoding()是一個嚴格的ASCII超集(或者,只要它的數字與ASCII數字匹配),你就會擺脫這種困境,但你真的不應該默默地依賴它。


接着,os.read(pipein,32)可以給你單個寫的結果,或者它可以給你多達32個單獨的寫操作結合在一起的結果。 write(高達PIPE_BUF)保證是原子的這一事實並不能幫助你 - 這只是意味着你不能在寫入的前半部分而不是在後半部分結束。

所以,最有可能的,你會得到21num1,然後在5秒後獲得另一個21num2,所以不是打印出來2每5秒鐘,你會打印出441每10秒。但即使這樣也不能保證。

與TCP插座一樣,管道爲byte streams, not message streams。這意味着你需要建立某種協議。


這裏有兩個非常明顯的選擇。首先,由於您已經讀取了(最多)32字節的固定記錄大小,爲什麼不寫出恰好32字節的固定記錄大小呢?只需將您的str行更改爲能夠生成正好爲32個字符的字符串的字符串,該字符串將在任何已編碼的編碼中編碼爲32個字節,並將解析爲適當值的單個整數。像這樣:

num1 = format(2, '32d') 
num2 = format(1, '32d') 

或者,每個記錄可以是一對以空格分隔的數字,記錄可以用換行符分隔。這是微不足道的解析。特別是因爲你沒有使用非阻塞的管道或任何東西,所以你可以在它們周圍放置一個文件對象並使其變得容易。

+0

非常感謝!!它現在變得更有意義。我實際上剛剛開始學習python幾周前,您的解決方案已經幫助了我很多! –