2011-12-06 27 views
5

我有一個可能長時間運行的程序,目前有4個進程,但可以配置更多。我已經使用python的logging研究了logging from multiple processes,並且使用了討論here的SocketHandler方法。我從來沒有任何問題有一個單一的記錄器(沒有套接字),但從我讀的內容來看,我被告知最終會意外失敗。據我所知,它不知道當你試圖同時寫入同一個文件時會發生什麼。我的代碼基本上是執行以下操作:來自多個進程的Python日誌記錄

import logging 
log = logging.getLogger(__name__) 

def monitor(...): 
    # Spawn child processes with os.fork() 
    # os.wait() and act accordingly 

def main(): 
    log_server_pid = os.fork() 
    if log_server_pid == 0: 
     # Create a LogRecordSocketServer (daemon) 
     ... 
     sys.exit(0) 
    # Add SocketHandler to root logger 
    ... 
    monitor(<configuration stuff>) 

if __name__ == "__main__": 
    main() 

所以我的問題是:我需要創建每個os.fork()後新log對象?現有的全球對象會發生什麼變化?

以我這樣做的方式,我是否解決了我試圖避免的問題(多個打開的文件/套接字)?這是否會失敗,爲什麼會失敗(我希望能夠判斷未來類似的實現是否會失敗)?

另外,從多個進程登錄到一個文件的「正常」(一個log=表達式)方法會失敗?它會引發IOError/OSError嗎?或者它只是沒有完全寫入文件的數據?

如果有人可以提供一個答案或鏈接來幫助我,那就太好了。謝謝。

FYI: 我測試在Mac OS X獅子和代碼最終可能會在CentOS 6的VM在Windows機器上運行(如果該事項)。無論我使用什麼解決方案都不需要在Windows上工作,但應該在基於Unix的系統上工作。

更新:這個問題已經開始擺脫日誌記錄的特定行爲,更多地處於linux在fork中對文件描述符做什麼的領域。我拿出了一本大學教科書,似乎如果你從兩個進程(不是分支之前)以附加模式打開一個文件,只要你的寫入沒有超過,他們都能夠正確地寫入文件實際的內核緩衝區(雖然可能需要使用行緩衝,但仍不確定)。這將創建2個文件表條目和一個v節點表條目。打開一個文件然後分叉不應該工作,但似乎只要你沒有像以前那樣超過內核緩衝區(我已經在之前的程序中完成了)。所以我想,如果你想獨立於平臺的多處理日誌記錄你使用套接字,並創建一個新的SocketHandler後,每個叉安全,因爲Vinay下面建議(這應該無處不在)。對我而言,由於我對運行我的軟件的操作系統有很強的控制力,因此我認爲我將使用一個FileHandler(默認情況下以附加模式打開,並在大多數操作系統上進行緩衝行)打開一個全局對象logopen的文檔說:「負緩衝意味着使用系統默認值,通常爲tty設備進行線路緩衝併爲其他文件進行完全緩衝,如果省略,則使用系統默認值。」或者我可以創建自己的日誌流以確保行緩衝。而僅僅是明確的,我確定有:

# Process A 
a_file.write("A\n") 
a_file.write("A\n") 
# Process B 
a_file.write("B\n") 

生產...

A\n 
B\n 
A\n 

,只要它不產生...

AB\n 
\n 
A\n 

維奈(或其他人),怎麼錯了我是誰?讓我知道。感謝您提供更多清晰/可靠的信息。

+0

線程和鎖對於這樣的事情很有用...... –

+0

我需要單獨的進程,因爲孩子們正在與外部設備進行通信,這些外部設備應該儘可能「快速」。 – daveydave400

+0

我更新了我的答案。 –

回答

2

我是否需要在每個os.fork()之後創建一個新的日誌對象?現有的全局日誌對象會發生什麼?

AFAIK全局日誌對象仍然指向父進程和子進程中的相同記錄器。所以你不需要創建一個新的。不過,我認爲你應該在fork()monitor()之後創建並添加SocketHandler,以便套接字服務器有四個不同的連接,每個子進程一個。如果你不這樣做,那麼在monitor()中派生的子進程將繼承SocketHandler及其父進程的套接字句柄,但我不確定它會不當行爲。該行爲可能取決於操作系統,您可能在OSX上很幸運。

以我這樣做的方式,我是否解決了我試圖避免的問題(多個打開的文件/套接字)?這是否會失敗,爲什麼會失敗(我希望能夠判斷未來類似的實現是否會失敗)?

我不希望失敗,如果你創建的最後fork()正如我上面建議後,插座連接到插座服務器,但我不知道在其他情況下的行爲被明確定義。你指的是多個打開的文件,但我沒有看到在你的僞代碼片斷中打開文件,只是打開套接字。

此外,從多個進程登錄到一個文件的「正常」(一個日誌=表達式)方法失敗了?它會引發IOError/OSError嗎?或者它只是沒有完全寫入文件的數據?

我認爲這種行爲並沒有很好的定義,但是人們可能會認爲失敗模式表現爲來自文件中不同進程的散佈日誌消息,例如,

Process A writes first part of its message 
Process B writes its message 
Process A writes second part of its message 

更新:如果您在您在您的評論中描述的方式使用FileHandler,事情不會那麼好,由於場景我上面描述:進程A和B都開始指着(因爲追加模式),但之後由於(例如,在一個多處理器上,但是甚至可能在一個單處理器上),一個進程可以(搶佔另一個進程並且)寫入共享文件句柄另一個過程已經完成。

+0

當我說多個文件時,我的意思是如果我已經完成了基本的FileHandler而不是SocketHandler。我和一位同事聊過,他提到如果日誌記錄在Linux上以append模式打開一個FileHandler,我應該可以(一個日誌對象,一個文件處理程序,多個分支)正常工作。思考?在fork之後創建SocketHandler是有道理的。 – daveydave400

+0

我已更新我的問題,謝謝。 – daveydave400

+0

我會接受你的答案,因爲在fork之後創建了SocketHandler,但我仍然不同意追加模式(內核應該使append寫入原子)。 – daveydave400