python中对mmap对象的多重访问

2024-03-28 14:31:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有很多文件,映射到内存(作为mmap对象)。在处理过程中,每个文件必须打开几次。如果只有一条线,它工作得很好。但是,当我尝试并行运行任务时,出现了一个问题:不同的线程不能同时访问同一个文件。此示例说明了问题:

import mmap, threading

class MmapReading(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        for i in range(10000):
            content = mmap_object.read().decode('utf-8')
            mmap_object.seek(0)
            if not content:
                print('Error while reading mmap object')

with open('my_dummy_file.txt', 'w') as f:
    f.write('Hello world')
with open('my_dummy_file.txt', 'r') as f:
    mmap_object = mmap.mmap(f.fileno(), 0, prot = mmap.PROT_READ)

threads = []
for i in range(64):
    threads.append(MmapReading())
    threads[i].daemon = True
    threads[i].start()
for thread in threading.enumerate():
    if thread != threading.current_thread():
        thread.join()

print('Mmap reading testing done!')

每当我运行这个脚本时,我会收到大约20条错误消息。在

有没有一种方法可以避免这个问题,除了为每个文件制作64个副本(在我的例子中这会消耗太多内存)?在


Tags: 文件内存inselfforobjectinitdef
3条回答

在另一个线程跳入并执行read()之前,seek(0)并不总是执行的。在

  1. 假设线程1执行读取,读取到文件末尾;seek(0)有 尚未执行。在
  2. 然后线程2执行读取。mmap中的文件指针仍然 在文件末尾。read()因此返回''。在
  3. 触发错误检测代码是因为content''。在

您可以使用切片来获得相同的结果,而不是使用read()。替换:

    content = mmap_object.read().decode('utf-8')
    mmap_object.seek(0)

^{pr2}$

content = mmap_object[:mmap_object.size()]也可以。在

锁定是另一种方法,但在这种情况下是不必要的。如果您想尝试,可以使用一个全局threading.Lock对象,并在实例化时将其传递给MmapReading。将lock对象存储在实例变量self.lock中。然后在读取/查找之前调用self.lock.acquire(),然后调用self.lock.release()。这样做会使您体验到非常明显的性能损失。在

from threading import Lock

class MmapReading(threading.Thread):
    def __init__(self, lock):
        self.lock = lock
        threading.Thread.__init__(self)

    def run(self): 
        for i in range(10000):
            self.lock.acquire()
            mmap_object.seek(0)
            content = mmap_object.read().decode('utf-8')
            self.lock.release()
            if not content:
                print('Error while reading mmap object')

lock = Lock()
for i in range(64):
    threads.append(MmapReading(lock))
.
.
.

请注意,我已经更改了读取和查找的顺序;首先执行查找更有意义,将文件指针定位在文件的开头。在

问题是单个mmap_对象在线程之间共享,因此线程A调用read,在到达seek之前,线程B也调用read,因此没有数据。在

您真正需要的是复制python mmap对象而不复制底层mmap的能力,但是我看不到这样做的方法。在

我认为除了重写对象实现之外,唯一可行的解决方案是为每个mmap对象使用一个锁(互斥锁等),以防止两个线程同时访问同一个对象。在

我不知道你需要从哪里开始mmap。mmap是一种在进程间共享数据的技术。你为什么不把内容读入内存(一次!)e、 作为列表?然后每个线程将使用它自己的迭代器集访问列表。另外,请注意Python中的GIL,它可以防止使用多线程进行任何加速。如果您想这样做,可以使用多处理(并且mmaped文件是有意义的,但实际上是在各个进程之间共享的)

相关问题 更多 >