Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对python中mmap对象的多重访问_Python_Multithreading_Mmap - Fatal编程技术网

对python中mmap对象的多重访问

对python中mmap对象的多重访问,python,multithreading,mmap,Python,Multithreading,Mmap,我有许多映射到内存的文件(如mmap对象)。在处理过程中,每个文件必须打开数次。如果只有一根线,它就可以正常工作。但是,当我尝试并行运行任务时,出现了一个问题:不同的线程不能同时访问同一个文件。此示例说明了该问题: import mmap, threading class MmapReading(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self)

我有许多映射到内存的文件(如
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个副本(在我的情况下,这会消耗太多内存)之外,还有什么方法可以避免这个问题吗?

在另一个线程跳入并执行
读取()之前,并不总是执行
查找(0)

  • 假设线程1执行读取,读取到文件的末尾<代码>搜索(0)
  • 已完成 尚未执行
  • 然后线程2执行读取。mmap中的文件指针仍然为空 在文件的末尾<因此,code>read()返回
    '
  • 触发错误检测代码是因为
    内容
    '
  • 您可以使用切片来获得相同的结果,而不是使用
    read()
    。替换:

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

    content=mmap\u对象[:mmap\u object.size()]
    也可以使用

    锁定是另一种方式,但在这种情况下没有必要。如果您想尝试,可以使用全局
    线程。在实例化时锁定
    对象并将其传递给
    MmapReading
    。将锁对象存储在实例变量
    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。mmap是一种在进程之间共享数据的技术。为什么不将内容读入内存(一次!),例如作为列表?然后,每个线程将使用自己的迭代器集访问列表。另外,请注意Python中的GIL,它可以防止使用多线程进行任何加速。如果需要,请使用多处理(然后使用mmaped文件是有意义的,但实际上是在各个进程之间共享的)

    问题是单个mmap_对象在线程之间共享,因此线程a调用读取,而在它到达寻道之前,线程B也调用读取,因此不获取任何数据

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


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

    我知道,会发生什么。问题是:如何避免它?@mhawke,为什么切片可以提供更好的性能?Idid提供了一些快速的google搜索,几乎什么也找不到。mmap除了在进程之间共享之外还有其他一些优势,例如,可以高效地随机访问操作系统管理分页的大文件。感谢您提及GIL。然而,由于实际线程中的外部应用程序调用,我确实获得了所需的加速。@mhawke啊,很有趣。
    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))
    .
    .
    .