随后异步解开大文件

问题描述

我有一个腌制列表目录,我想依次加载它,用作操作的一部分,然后丢弃。腌制后的文件大小约为0.75-2GB,我可以随时在内存中加载一个数字,尽管距离所有文件都不远。每个腌制的文件代表一天的数据。

当前,解进程占用程序运行时的很大一部分。我建议的解决方案是加载第一个文件,然后在该文件上运行操作时,异步加载列表中的下一个文件

我想到了两种方法可以做到这一点:1)线程化和2)Asyncio。我尝试了这两种方法,但似乎都没有用。以下是我(基于尝试)的基于线程的解决方案的实现。

import os
import threading
import pickle

class DataSource:
    def __init__(self,folder):
        self.folder = folder
        self.next_file = None

    def get(self):
        if self.next_file is None:
            self.load_file()
        data = self.next_file
    
        io_thread = threading.Thread(target=self.load_file,daemon=True)
        io_thread.start()

        return data

    def get_next_file(self):
        for filename in sorted(os.listdir(self.folder)):
            yield self.folder + filename

    def load_file(self):
        self.next_file = pickle.load(open(next(self.get_next_file()),"rb"))

主程序将调用 DataSource()。get()来检索每个文件。第一次加载文件时, load_file()会将文件加载到 next_file 中,并在其中存储文件。然后,线程 io_thread 应该将每个连续的文件加载到 next_file 中,以根据需要通过 get()返回。

启动的线程确实可以完成某些工作(它消耗大量的RAM,约60GB),但似乎没有更新 next_file

有人可以建议为什么这不起作用吗?另外,是否有更好的方法来达到此效果

谢谢

解决方法

DataSource().get()似乎是您的第一个问题:这意味着您将始终创建DataSource类的新实例,并且只会加载第一个文件,因为您再也不会调用同一DataSource对象实例了,您将继续下一个文件。也许您打算按照以下方式进行操作:

datasource = DataSource()
while datasource.not_done():
    datasource.get() 

共享完整代码非常有用,最好在repl.it或可执行代码的地方共享。

此外,如果您想获得更好的性能,那么我可能值得研究一下多处理模块,因为Python会使用全局解释器锁(GIL)阻止某些操作,从而即使一次运行多个线程,一次也只能运行一个线程。 CPU核。但这可能不是问题,因为从磁盘读取可能是瓶颈,我想Python在执行底层本机代码以从文件系统读取时会释放锁。

我也很好奇您如何使用asyncio来腌制..我猜您先从文件中读取了腌制的mem,然后在完成后解开,同时在加载过程中进行了其他处理。看来它可以很好地工作。

最后,我将添加调试打印以查看发生了什么。

更新:下一个问题似乎是您错误地使用了get_next_file生成器。每次都使用self.get_next_file()在此处创建一个新的生成器,因此您只会加载第一个文件。您只应创建一次生成器,然后在其上调用next()。也许这有助于理解,也可以在replit上查看:

def get_next_file():
        for filename in ['a','b','c']:
            yield filename

for n in get_next_file():
  print(n)

print("---")

print(next(get_next_file()))
print(next(get_next_file()))
print(next(get_next_file()))

print("---")

gen = get_next_file()
print(gen)
print(next(gen))
print(next(gen))
print(next(gen))

输出:

a
b
c
---
a
a
a
---
<generator object get_next_file at 0x7ff4757f6cf0>
a
b
c

https://repl.it/@ToniAlatalo/PythonYieldNext#main.py

同样,调试打印将帮助您了解正在发生的事情,何时加载的文件等。