簡體   English   中英

'unlink()' 在 Windows 上的 Python 共享內存中不起作用

[英]'unlink()' does not work in Python's shared_memory on Windows

我正在使用 Python 3.8 的新shared_memory模塊,並且無法在不終止使用它的進程的情況下釋放共享的 memory。

在創建並使用共享 memory 的塊shm之后,我在所有進程中通過shm.close()關閉它,最后在主進程中通過shm.unlink釋放它。 但是,資源監視器顯示 memory 在程序終止之前不會被釋放 這對我來說是個嚴重的問題,因為我的程序需要運行很長時間。 使用以下程序可以在 Windows/Python 3.8 上重現該問題:

from multiprocessing import shared_memory, Pool
from itertools import repeat
from time import sleep

def fun(dummy, name):
    
    # access shared memory
    shm = shared_memory.SharedMemory(name=name)
    
    # do work
    sleep(1)
    
    # release shared memory
    shm.close()
    
    return dummy

def meta_fun(pool):
    
    # create shared array
    arr = shared_memory.SharedMemory(create=True, size=500000000)
    
    # compute result
    result = sum(pool.starmap(fun, zip(range(10), repeat(arr.name))))
    
    # release and free memory
    arr.close()
    arr.unlink()
    
    return result

if __name__ == '__main__':
    
    # use one Pool for many method calls to save the time for repeatedly
    # creating processes
    with Pool() as pool:
        for i in range(100):
            print(meta_fun(pool))

注意:執行此腳本時,您可能會很快填滿整個 memory。請注意資源監視器中的“虛擬內存”面板。

在做了一些研究之后,我發現 (1) unlink() function 在 Windows 上什么都不做

def unlink(self):
    """Requests that the underlying shared memory block be destroyed.
    In order to ensure proper cleanup of resources, unlink should be
    called once (and only once) across all processes which have access
    to the shared memory block."""
    if _USE_POSIX and self._name:
        from .resource_tracker import unregister
        _posixshmem.shm_unlink(self._name)
        unregister(self._name, "shared_memory")

和 (2) Windows 似乎在創建/使用它的進程停止后釋放共享的 memory(請參閱此處此處的評論)。 這可能是 Python 沒有明確處理的原因。

作為回應,我通過重復保存和重復使用相同的共享 memory 塊而不取消鏈接來構建一個丑陋的解決方法。 顯然,這不是一個令人滿意的解決方案,尤其是當所需的 memory 塊的大小動態變化時。

有沒有辦法可以手動釋放 Windows 上共享的 memory?

這是multiprocessing模塊中的一個錯誤,報告為問題 40882 有一個開放的 pull request 可以修復它, PR 20684 ,但顯然它的合並速度很慢。

錯誤如下:在SharedMemory.__init__中,我們調用MapViewOfFile API 沒有相應的UnmapViewOfFile ,並且mmap object 也不擁有它的所有權(它自己再次映射塊)。

同時,您可以對shared_memory模塊進行猴子修補,以便在構建mmap后添加缺少的UnmapViewOfFile調用。 您可能不得不依賴ctypes ,因為_winapi模塊不導出UnmapViewOfFile ,盡管導出MapViewOfFile (.): 類似這樣的東西(未測試):

import ctypes, ctypes.wintypes
import multiprocessing, multiprocessing.shared_memory

UnmapViewOfFile = ctypes.windll.kernel32.UnmapViewOfFile
UnmapViewOfFile.argtypes = (ctypes.wintypes.LPCVOID,)
UnmapViewOfFile.restype = ctypes.wintypes.BOOL

def _SharedMemory_init(self, name=None, create=False, size=0):
    ... # copy from SharedMemory.__init__ in the original module
                try:
                    p_buf = _winapi.MapViewOfFile(
                        h_map,
                        _winapi.FILE_MAP_READ,
                        0,
                        0,
                        0
                    )
                finally:
                    _winapi.CloseHandle(h_map)
                try:
                    size = _winapi.VirtualQuerySize(p_buf)
                    self._mmap = mmap.mmap(-1, size, tagname=name)
                finally:
                    UnmapViewOfFile(p_buf)
    ... # copy from SharedMemory.__init__ in the original module

multiprocessing.shared_memory.SharedMemory.__init__ = _SharedMemory_init

將上面的代碼放入一個模塊中,並記住在使用multiprocessing模塊中的任何內容之前加載它。 或者,您可以直接編輯multiprocessing模塊目錄中的shared_memory.py文件以包含所需的UnmapViewOfFile調用。 這不是最干凈的解決方案,但無論如何它都是暫時的(著名的遺言); 長期的解決方案是在上游固定這個(顯然正在進行中)。

也許沒有發現,但 unlink 仍然不允許我在 user3840170 給出的路徑之后重新創建具有相同名稱的 shm。

del 為我工作(Py3.10)

暫無
暫無

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

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