簡體   English   中英

使用Python多處理管理器(BaseManager / SyncManager)與遠程計算機共享隊列時斷管

[英]Broken Pipe when Using Python Multiprocessing Managers (BaseManager/SyncManager) to Share Queue with Remote Machines

在上個月,當我們嘗試使用它來共享幾個不同(linux)計算機之間的隊列時,我們遇到了Python 2.6.x多處理程序包的持續問題。 我已經直接向Jesse Noller提出了這個問題,因為我們還沒有發現任何可以解釋StackOverflow,Python文檔,源代碼或其他在線問題的內容。

我們的工程師團隊無法解決這個問題,我們已經向python用戶群中的很多人提出了這個問題,但無濟於事。 我希望有人可以提供一些見解,因為我覺得我們做的事情不正確,但是太接近問題而不能看到它是什么。

這是症狀:

Traceback (most recent call last):
  File "/var/django_root/dev/com/brightscope/data/processes/daemons/deferredupdates/servers/queue_server.py", line 65, in get_from_queue
    return queue, queue.get(block=False)
  File "<string>", line 2, in get
  File "/usr/local/lib/python2.6/multiprocessing/managers.py", line 725, in _callmethod
    conn.send((self._id, methodname, args, kwds))
IOError: [Errno 32] Broken pipe

(我正在顯示我們的代碼在共享隊列對象上調用queue.get()的位置,由擴展SyncManger的管理器托管)。

這個問題的特殊之處在於,如果我們在一台機器上連接到這個共享隊列(讓我們稱之為這machine A ),即使是從大量並發進程中,我們似乎也不會遇到問題。 只有當我們從其他機器連接到隊列(再次使用擴展多處理SyncManager並且當前不添加其他功能的類)時(讓我們調用這些machines B and C )並運行大量項目進出隊列在我們遇到問題的同時。

就好像python的多處理包處理本地連接(即使它們仍然使用相同的manager.connect()連接方法)一樣,它可以從machine A工作,但是當從至少一machines B or C同時進行遠程連接時machines B or C我們得到一個Broken pipe錯誤。

在我的團隊所做的所有閱讀中,我們認為問題與鎖定有關。 我們認為也許我們不應該使用Queue.Queue ,而是使用multiprocessing.Queue ,但我們切換並且問題仍然存在(我們還注意到SyncManager自己的共享隊列是Queue.Queue的一個實例)。

我們正在研究如何調試問題,因為它很難重現,但確實經常發生(如果我們從隊列中插入和.get()大量項目,則每天多次)。

我們創建的方法get_from_queue嘗試使用隨機休眠間隔重試從隊列中獲取項目~10次,但似乎如果它失敗一次,它將失敗十次(這使我相信.register()和。)。 connect()到一個管理器可能沒有給服務器另一個套接字連接,但我無法通過閱讀文檔或查看Python內部源代碼來確認這一點。

任何人都可以提供任何洞察我們可能會在哪里或我們如何跟蹤實際發生的事情?

如果使用multiprocessing.BaseManagermultiprocessing.SyncManager管道損壞的情況下我們如何啟動新連接?

我們怎樣才能首先防止破裂的管道?

僅供參考。如果其他人遇到同樣的錯誤,在與Python的核心開發團隊的Ask Solem和Jesse Noller進行了廣泛的咨詢后,看起來這實際上是當前python 2.6.x中的一個錯誤(可能是2.7+,可能是3.x) )。 他們正在研究可能的解決方案,並且可能會在未來的Python版本中包含修復程序。

我遇到了同樣的問題,即使在python 2.7.1中連接localhost也是如此。 經過一天的調試后,我找到了原因和解決方法:

原因:BaseProxy類具有緩存連接的線程本地存儲,該連接將重新用於將來的連接,即使在創建新Manager時也會導致“管道損壞”錯誤

解決方法:在重新連接之前刪除緩存的連接。 將代碼添加到引發異常的行上的try-except子句,然后重試它。

from multiprocessing.managers import BaseProxy

...

if address in BaseProxy._address_to_local:
    del BaseProxy._address_to_local[address][0].connection

address是用於連接到多處理管理器的主機名/ IP。 如果你沒有明確設置它,通常應該是"localhost"

此外,您可以嘗試捕獲子進程中的異常,以便它不應嘗試關閉UN-expected的連接。 同樣發生在我身上,最后我不得不壓制錯誤,以免管道突然關閉。

在中斷多處理過程后,我在交互式Jupyter筆記本(Python 3.6.8)中遇到了同樣的問題。

我的短期修復是重新實例化ManagerNamespace對象

from multiprocessing import Manager

mgr = Manager()
ns = mgr.Namespace()

指南

避免終止進程

使用Process.terminate方法停止進程可能會導致進程當前使用的任何共享資源(例如鎖,信號量,管道和隊列)被破壞或不可用於其他進程。

因此,最好只考慮在從不使用任何共享資源的進程上使用Process.terminate。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM