[英]Broken Pipe when Using Python Multiprocessing Managers (BaseManager/SyncManager) to Share Queue with Remote Machines
[英]When does multiprocessing.BaseManager use RemoteError?
我有一個用於CPython的C擴展模塊。 我需要多個uWSGI worker才能在這個模塊中共享一個對象的單個實例。 我正在使用multiprocessing.BaseManager
的自定義子類來完成此任務,基於此答案描述了一個非常類似的解決方案。
下面的第一個腳本是wifi.manager
( wifi.controller.IFace
是要共享的對象)。 我使用python3 wifi/manager.py
運行它,然后啟動Web服務器,它運行第二個代碼段中的代碼以獲取共享對象實例。
WIFI / manager.py:
#!/usr/bin/env python3
from multiprocessing.managers import BaseManager
# .register() changes the class itself. We don't want to do that to BaseManager.
class WifiManager(BaseManager):
pass
if __name__ == '__main__':
# If we are executed as a script (python3 manager.py), start the server
import atexit
from multiprocessing import Lock
import wifi.controller
ifaces_lock = Lock()
ifaces = dict()
def get_iface(iface_path):
with ifaces_lock:
if iface_path not in ifaces:
# Control interface isn't open. Open it.
iface = wifi.controller.IFace(iface_path)
ifaces[iface_path] = iface
return ifaces[iface_path]
def close_ifaces():
for iface in ifaces.values():
iface.close()
WifiManager.register('get_iface', get_iface)
atexit.register(close_ifaces)
manager = WifiManager(address=('127.0.0.1', 2437), authkey=b'wifimanager')
server = manager.get_server()
server.serve_forever()
else:
# If we are imported, provide the WifiManager class ready for clients to use
WifiManager.register('get_iface')
來自網絡應用程序的代碼段:
from wifi.manager import WifiManager
...
wmanager = WifiManager(address=('127.0.0.1', 2437), authkey=b'wifimanager')
wmanager.connect()
iface = wmanager.get_iface(iface_path)
iface.scan() # And other code using the iface object
wifi.controller.IFace
對象有時會引發異常,無論是內置的(主要是OSError
)還是自己的wifi.controller.WifiError
異常。 有時,我希望能夠在Web應用程序中捕獲這些內容,以向客戶端顯示有意義的錯誤頁面。 但是,我注意到有時候,這些異常會被捕獲並且在Web應用程序中引發相同的異常(例如WifiError
)。 其他時候,Web應用程序會獲得一個multiprocessing.managers.RemoteError
,其中來自管理器的回溯存儲為字符串。
問題是,我怎么知道它什么時候會引發原始異常以及何時會引發RemoteError
,所以我知道要捕獲哪一個? 所有Python文檔都說 :
如果調用引發異常,則由_callmethod()重新引發。 如果在管理器的進程中引發了一些其他異常,則會將其轉換為RemoteError異常並由_callmethod()引發。
這對我來說不是很清楚,我無法弄清楚它是如何與我觀察到的行為對齊的。
我相信我已經明白了。 我仍然不是百分百肯定,但看到這個問題沒有得到很多關注,我想我會繼續並添加一個答案,以防未來的讀者偶然發現。
在原始遠程調用期間在WifiManager
中發生的異常會被引發為RemoteError
。 在這種情況下,這意味着在Web應用程序中此行期間遠程端的異常:
iface = wmanager.get_iface(iface_path)
之后,Web應用程序不再直接與WifiManager
交互。 它只與iface
( 代理對象)進行交互。 如果代理對象(或更准確地說,它的引用對象)在遠程端引發異常, RemoteError
在Web應用程序中引發相同的異常,而不是RemoteError
。 因此,這意味着如果此行導致例如WifiError
或OSError
,那么這些是您將捕獲的異常:
iface.scan() # And other code using the iface object
因此,總而言之,當遠程端出現異常時,對BaseManager
(或子類)的調用會引發RemoteError
。 對代理對象的調用會引發原始異常的副本。
請記住,這個答案是基於我的觀察,而不是我對情況的全面和全面的了解,所以我可能沒有意識到這里有一些問題。 如果有人知道的更好,請糾正我。 但這描述了我觀察到的行為,並且似乎與問題中引用的文檔一致。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.