2014-09-05 151 views
2

我有一個Python多處理應用程序,它啓動使用多處理API的「工作人員」。主進程本身是由一個不用Python編寫的服務進程啓動的。工作人員可能會使用subprocess.Popen開始其他非Python子流程。Python子進程阻止在主進程中阻止從標準輸入讀取

爲了清楚起見,這是整個過程的層次結構:

  • service.exe:服務過程(天然EXE)
    • python.exe:Python的主處理(以下程序)
      • 蟒.exe:Python子進程(任務函數由進程啓動)
        • subprocess.exe:本機子進程(請參閱下面的說明)

當服務過程停止,它必須告訴Python的進程退出。我正在使用標準輸入。好處是,如果服務進程崩潰或被終止,那麼Python進程的標準輸入就會關閉,所以它將退出,並且不會有孤立進程。

import multiprocessing 
import time 
import sys 


def task(): 
    print("Task started...") 
    # TODO: Start a native process here using Subprocess.popen 
    time.sleep(3) 
    print("Task ended") 

if __name__ == '__main__': 
    process = multiprocessing.Process(target=task) 
    process.start() 

    # time.sleep(3) # "workaround" 
    sys.stdin.read() 

    print("Terminating process...") 
    process.terminate() 

然而,似乎當我添加sys.stdin.read(),Python的子進程啓動,但它不會做任何事情。它似乎掛起。

(壞)解決方法是在從標準輸入讀取之前添加time.sleep(3)。然後上面的程序工作。但是,似乎Python子進程啓動的子進程仍然可以阻塞,只有在主進程中執行阻塞讀取時,它們纔會阻塞。

在所有系統上都不會發生此問題。它在一臺Windows 8機器上被觀察到,並且從未在另一臺Windows機器上發生過。我正在使用Python 2.7.2。

我的問題是:如何在主進程中的阻塞讀取影響子進程?子過程不應該獨立於我在主過程中做的任何事情而開始和運行嗎? (我只想了解這個問題,如果你找到一個更好的解決方案來停止服務進程中的Python進程,我會很感激,但這是奇怪的阻止行爲,給我做惡夢)

回答

0

你的子進程aren不掛。當我使用多處理庫時,我最喜歡使用的調試技術之一是讓子流程放棄文本文件而不是打印到標準輸出,這樣可以避免管道的所有複雜問題,比如想知道子流程是否繼承同樣的標準輸入/輸出,全管道等如果我們修改你的任務是以下幾點:

def task(): 
    with open('taskfile.txt', 'w') as fo: 
     fo.write("Task started...") 
     # TODO: Start a native process here using Subprocess.popen 
     time.sleep(3) 
     fo.write("Task ended") 

它產生包含以下文本文件「taskfile.txt」:

任務開始...任務結束

因此,您的任務正在運行並正常退出。Main只是在等待來自stdin的輸入。我懷疑你沒有看到「Task started ...」筆記,因爲使用multiprocessing.Process()啓動的進程有自己的標準輸入和標準輸出管道,它們沒有連接到與main相同的控制檯。

+0

在我的真實應用程序中(上面的代碼只是一個簡單的測試程序,我希望能夠重現該問題),子進程寫入數據庫以將「作業」標記爲「進行中」。當且僅當主進程阻止從標準輸入讀取時,纔會發生這種情況。 但是,我同意上述示例可能不會重現實際問題,或者出於其他原因可能無法打印「任務已結束」。 我也忘了提及一位同事無法在他的機器上重現問題。如果我找到時間,我會嘗試使用示例程序的調試技巧... – 2014-09-10 20:03:32

+0

您在您的問題中提出的假設是正確的:從主標準輸入讀取的阻止讀取應該對您的子流程執行沒有影響。嘗試添加幾個文本文件寫入到您的子過程中,您將添加用於調試的打印語句的相同方式,並嘗試縮小子流程的掛起位置。如果您無法用他們提供的信息解決問題,請嘗試在問題中添加一些真實的代碼。看看你是如何啓動子過程以及任務函數中的所有內容(包括掛起的語句)將會很有幫助。 – skrrgwasme 2014-09-10 20:08:05

+0

@FlorianWinter你在使用什麼樣的數據庫?本機支持的數據庫之一?在沒有看到任何與數據庫相關的代碼的情況下,我會建議檢查以確保您的主進程在等待stdin時不保存任何數據庫資源,並確保您的子進程修改數據庫的方式是線程安全的。如果兩個子進程之間發生衝突,這兩個進程都試圖同時修改數據庫,則可能是數據丟失或死鎖。 – skrrgwasme 2014-09-13 17:44:56