2013-02-01 70 views
1

在python中,如果在父進程中配置了日誌記錄器,那麼子進程是否也會獲得該日誌記錄器?更清楚的是,在我的應用程序中,我通過執行logger = logging.getlogger()併爲其添加處理程序來爲父進程配置根記錄器。現在,當一個子進程分叉,它確實是記錄器是否可以通過父進程和子進程訪問?

logger = logging.getlogger() 
logger.info("dfsdf") 

然後根據父級的根記錄器處理所有日誌。我沒有爲孩子配置根記錄器。這怎麼可能?他們是兩個不同的過程,他們怎麼能有相同的記錄器?

回答

3

分叉進程時,它'繼承'父進程內存,包括記錄器配置。

Fork Wikipedia page

叉操作創建爲孩子獨立的地址空間。子進程具有父進程的所有內存段的精確副本,但是如果實現了寫時複製語義,實際的物理內存可能不會被分配(即,兩個進程可能共享相同的物理內存段) 。父進程和子進程都擁有相同的代碼段,但彼此獨立執行。

這不是Python獨有的;這發生在分叉的任何UNIX進程中,可以用C,Perl或Python實現。

multiprocessing module使用它(在支持它的平臺上)快速創建新進程。

請注意,繼承記錄器可能會導致競爭條件; logging模塊只知道線程安全性;它使用線程鎖來序列化對處理程序的訪問,但該鎖不是跨進程共享的(子進程中的所有內容都是副本,而不是同一個對象)。

這意味着,當您同時記錄來自父代和子代的消息時,日誌條目最終可能會混合在一起,因爲操作系統會在將日誌條目寫入文件的同時在兩個進程之間切換。

+0

感謝您澄清我的疑問。如果我願意,這是否使我能夠直接在子進程中使用父記錄器,而不是在分叉時將其作爲參數傳遞給父進程?這是一個正確的方法嗎? – alice

+0

@alice:可能不是;我已經更新了我的答案。 –

+0

您可以使用fork()的結果來執行post-fork操作來清理像這樣的情況(重定向日誌),或者通過使用log4j之類的API使用日誌記錄進程。 –

2

有兩件事可能會讓你感到困惑。

  1. 「同一個記錄器對象。」當然,對象不一樣,就像子進程中的所有對象與父進程中的對象不一樣。子進程是具有獨立地址空間的父進程的完整副本。這意味着他們不共享任何內存。如果一個對象位於父進程中的某個內存地址處,則在fork之後,子進程將具有位於相同地址的相同對象。但是,地址在不同的地址空間中,內存不共享,並且分叉完成後對象不相互關聯。所以,你的問題的簡短答案是:對象不一樣。

  2. 記錄器對象可能在fork完成之前打開一個文件。打開的文件由子進程繼承。這意味着這兩個進程有一個文件的兩個文件句柄。這是一個同步問題。

UPD:我已經瀏覽了我的Python 2.7安裝中的日誌記錄模塊源代碼。它使用threading.RLock來同步日誌訪問。這意味着您無法在父進程和子進程中安全地使用相同的日誌文件。您必須關心具有不同日誌的子進程和父進程。它是一個守護程序嗎?如果是,通常父進程不需要太多的日誌記錄,可以使用單獨的日誌記錄器。

+0

'threading.RLock'是否支持多個進程?我覺得它不應該。 –

+1

@ m.brindley:它沒有。該鎖與其他所有內容一起被複制到子進程。父級和子級進程鎖不通信。 –

+0

它只用於同步線程,根本不知道其他進程。所以日誌可能會損壞。 – Ellioh

相關問題