मैं पायथन 3.8 के नए shared_memory
मॉड्यूल का उपयोग कर रहा हूं और साझा मेमोरी को बिना प्रक्रियाओं को समाप्त किए मुक्त करने में विफल हूं।
साझा स्मृति का एक ब्लॉक shm
बनाने और उपयोग करने के बाद, मैं इसे सभी प्रक्रियाओं में shm.close()
के माध्यम से बंद कर देता हूं और अंत में इसे मुख्य प्रक्रिया में shm.unlink
के माध्यम से मुक्त करता हूं। हालांकि, संसाधन मॉनिटर मुझे दिखाता है कि कार्यक्रम समाप्त होने तक स्मृति मुक्त नहीं होती है। यह मेरे लिए एक गंभीर समस्या है, क्योंकि मेरे कार्यक्रम को लंबे समय तक चलने की जरूरत है। निम्न प्रोग्राम के साथ विंडोज/पायथन 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))
सावधानी: इस स्क्रिप्ट को निष्पादित करते समय, आप जल्दी से अपनी पूरी मेमोरी भर सकते हैं! संसाधन मॉनीटर में "वर्चुअल मेमोरी" पैनल देखें।
कुछ शोध करने के बाद, मुझे पता चला कि (1) unlink()
फ़ंक्शन 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) विंडोज़ साझा स्मृति को मुक्त करने लगता है जब इसे बनाने/उपयोग करने वाली प्रक्रियाएं बंद हो जाती हैं (टिप्पणियां देखें यहां और यहां)। यह पाइथन के स्पष्ट रूप से इसे संभालने का कारण नहीं हो सकता है।
जवाब में मैंने एक ही साझा मेमोरी ब्लॉक को बार-बार अनलिंक किए बिना सहेजने और पुन: उपयोग करके एक बदसूरत कामकाज बनाया है। जाहिर है, यह एक संतोषजनक समाधान नहीं है, खासकर यदि आवश्यक मेमोरी ब्लॉक के आकार गतिशील रूप से बदलते हैं।
क्या ऐसा कोई तरीका है जिससे मैं विंडोज़ पर साझा की गई मेमोरी को मैन्युअल रूप से खाली कर सकूं?
1 उत्तर
यह multiprocessing
मॉड्यूल में एक बग है, जिसकी रिपोर्ट समस्या 40882 के रूप में की गई थी। एक खुला पुल अनुरोध है जो इसे ठीक करता है, PR 20684, हालांकि जाहिर तौर पर यह धीमा रहा है विलय करने के लिए।
बग इस प्रकार है: SharedMemory.__init__
में, हमारे पास एक आह्वान noreferrer">MapViewOfFile
API बिना संगत UnmapViewOfFile
, और mmap
ऑब्जेक्ट भी इसका स्वामित्व नहीं लेता है (यह ब्लॉक को फिर से अपने आप मैप करता है)।
इस बीच, आप 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
मॉड्यूल से कुछ भी उपयोग करने से पहले इसे लोड करना याद रखें। वैकल्पिक रूप से, आप आवश्यक UnmapViewOfFile
कॉल को शामिल करने के लिए multiprocessing
मॉड्यूल की निर्देशिका में सीधे shared_memory.py
फ़ाइल को संपादित कर सकते हैं। यह सबसे साफ समाधान नहीं है, लेकिन यह वैसे भी अस्थायी होना है (प्रसिद्ध अंतिम शब्द); दीर्घकालिक समाधान यह है कि यह निश्चित अपस्ट्रीम (जैसा कि स्पष्ट रूप से चल रहा है)।
संबंधित सवाल
नए सवाल
python
पायथन एक बहु-प्रतिमान है, गतिशील रूप से टाइप किया हुआ, बहुउद्देशीय प्रोग्रामिंग भाषा है। यह एक साफ और एक समान वाक्यविन्यास सीखने, समझने और उपयोग करने के लिए त्वरित होने के लिए डिज़ाइन किया गया है। कृपया ध्यान दें कि अजगर 2 आधिकारिक तौर पर 01-01-2020 के समर्थन से बाहर है। फिर भी, संस्करण-विशिष्ट पायथन सवालों के लिए, [अजगर -२.०] या [अजगर -३.x] टैग जोड़ें। पायथन वेरिएंट (जैसे, ज्योथन, PyPy) या लाइब्रेरी (उदा।, पांडस और न्यूमपी) का उपयोग करते समय, कृपया इसे टैग में शामिल करें।