为什么上下文管理器不关闭文件描述符?

时间:2017-11-02 21:59:01

标签: python windows python-3.x mmap contextmanager

我正在尝试创建一个使用def cutRod(price, n): val = [0 for x in range(n+1)] val[0] = 0 output = list() for i in range(1, n+1): max_val = 0 cur_max_index = -1 for j in range(i): cur_val = price[j] + val[i-j-1] if(cur_val>max_val): max_val = cur_val #store current max cur_max_index = j #and index if cur_max_index != -1: output.append(cur_max_index) #append in output index list val[i] = max_val print(output) #print array return val[n] 的上下文管理器,它本身就是一个上下文管理器。最初我有一个愚蠢的打开文件问题[为什么mmap不关闭相关文件(得到PermissionError:[WinError 32])?] here并且答案快速解释为什么它不是按需工作。

鉴于这些信息,我尝试了两种不同的方法来纠正这个问题,但没有一种方法可以解决。

第一种方法是使用mmap的{​​{1}}装饰器:

contextlib

但结果是:

@contextmanager

在下一次尝试中,我尝试了显式创建上下文管理器类:

from contextlib import contextmanager
import os
import mmap

#contextmanager
def memory_map(filename, access=mmap.ACCESS_WRITE):
    size = os.path.getsize(filename)
    fd = os.open(filename, os.O_RDWR)
    print('about to yield')
    with mmap.mmap(fd, size, access=access) as m:
        yield m
    print('in finally clause')
    os.close(fd)  # Close the associated file descriptor.

test_filename = 'data'

# First create the test file.
size = 1000000
with open(test_filename, 'wb') as f:
     f.seek(size - 1)
     f.write(b'\x00')

# Read and modify mmapped file in-place.
with memory_map(test_filename) as m:  # Causes AttributeError: __enter__
    print(len(m))
    print(m[0:10])
    # Reassign a slice.
    m[0:11] = b'Hello World'

# Verify that changes were made
print('reading back')
with open(test_filename, 'rb') as f:
     print(f.read(11))

# Delete test file.
# Causes:
# PermissionError: [WinError 32] The process cannot access the file because it
# is being used by another process: 'data'
os.remove(test_filename)

这使得它更进一步,但是Traceback (most recent call last): File "memory_map.py", line 27, in <module> with memory_map(test_filename) as m: # Causes AttributeError: __enter__ AttributeError: __enter__ 又回来了 - 这让我感到困惑,因为文件描述符 在该版本中已关闭,正如您在输出中看到的那样:

import os
import mmap

class MemoryMap:
    def __init__(self, filename, access=mmap.ACCESS_WRITE):
        print('in MemoryMap.__init__')
        size = os.path.getsize(filename)
        self.fd = os.open(filename, os.O_RDWR)
        self.mmap = mmap.mmap(self.fd, size, access=access)

    def __enter__(self):
        print('in MemoryMap.__enter__')
        return self.mmap

    def __exit__(self, exc_type, exc_value, traceback):
        print('in MemoryMap.__exit__')
        os.close(self.fd)  # Close the associated file descriptor.
        print('  file descriptor closed')


test_filename = 'data'

# First create the test file.
size = 1000000
with open(test_filename, 'wb') as f:
     f.seek(size - 1)
     f.write(b'\x00')

# Read and modify mmapped file in-place.
with MemoryMap(test_filename) as m:
    print(len(m))
    print(m[0:10])
    # Reassign a slice.
    m[0:11] = b'Hello World'

# Verify that changes were made
print('reading back')
with open(test_filename, 'rb') as f:
     print(f.read(11))

# Delete test file.
# Causes PermissionError: [WinError 32] The process cannot access the file
# because it is being used by another process: 'data'
os.remove(test_filename)

所以看来我再次陷入困境。关于什么是错的(以及如何修复它)的任何想法?另外,如果你有意见,他们都可以修好,哪一个更好?

解决方案

两个片段都有错误。这首先是一个简单的印刷错误。 PermissionError装饰者被注释掉了。应该是:

in MemoryMap.__init__
in MemoryMap.__enter__
1000000
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
in MemoryMap.__exit__
  file descriptor closed
reading back
b'Hello World'
Traceback (most recent call last):
  File "memory_map2.py", line 47, in <module>
    os.remove(test_filename)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'data'

第二个是因为contextmanger 本身未在@contextmanager # Leading "#" changed to "@". def memory_map(filename, access=mmap.ACCESS_WRITE): size = os.path.getsize(filename) fd = os.open(filename, os.O_RDWR) ,,, 方法中关闭,只是关联的文件描述符。从来没有发生过这种情况,因为提出的例外情况与第一种情况相同。

mmap

1 个答案:

答案 0 :(得分:2)

如果是第二次尝试,则需要关闭内存映射文件:

def __exit__(self, exc_type, exc_value, traceback):
    self.mm.close()
    print('in MemoryMap.__exit__')
    os.close(self.fd)  # Close the associated file descriptor.
    print('  file descriptor closed')