【问题标题】:Do all iterators cache? How about csv.Reader?所有迭代器都缓存吗? csv.Reader 怎么样?
【发布时间】:2011-07-01 10:07:06
【问题描述】:

我们知道下面的代码只是逐行加载数据,而不是将它们全部加载到内存中。即,已读取的行将以某种方式标记为操作系统的“可删除”

def fileGen( file ):
    for line in file:
        yield line

with open("somefile") as file:
    for line in fileGen( file ):
        print line

但是如果我们将fileGen的定义修改为following,我们是否可以验证这是否仍然正确?

def fileGen( file ):
    for line in csv.Reader( file ):
        yield line

我们如何知道 csv.Reader 是否会缓存它加载的数据?谢谢

问候, 约翰

【问题讨论】:

    标签: python caching memory csv iterator


    【解决方案1】:

    找出csv.reader 在做什么的最可靠方法是阅读源代码。参见_csv.c,第 773 行以后。您会看到 reader 对象有一个指向底层迭代器(通常是文件迭代器)的指针,并且每次需要另一行时它都会调用 PyIter_Next。所以它不会提前读取或缓存它加载的数据。

    了解csv.reader 在做什么的另一种方法是制作一个模拟文件对象,该对象可以在查询时报告。例如:

    class MockFile:
        def __init__(self): self.line = 0
        def __iter__(self): return self
        def next(self):
            self.line += 1
            print "MockFile line", self.line
            return "line,{0}".format(self.line)
    
    >>> r = csv.reader(MockFile())
    >>> next(r)
    MockFile line 1
    ['line', '1']
    >>> next(r)
    MockFile line 2
    ['line', '2']
    

    这证实了我们从阅读csv 源代码中学到的东西:它只在调用自己的next 方法时从底层迭代器请求下一行。


    John 明确表示(参见 cmets),他关心的是 csv.reader 是否保持这些行处于活动状态,从而防止它们被 Python 的内存管理器收集。

    同样,您可以阅读代码(最可靠)或尝试进行实验。如果您查看_csv.cReader_iternext 的实现,您会看到lineobj 是底层迭代器返回的对象的名称,并且在代码的每条路径上都有对Py_DECREF(lineobj) 的调用.所以csv.reader 不会让lineobj 活着。

    这里有一个实验来证实这一点。

    class FinalizableString(string):
        """A string that reports its deletion."""
        def __init__(self, s): self.s = s
        def __str__(self): return self.s
        def __del__(self): print "*** Deleting", self.s
    
    class MockFile:
        def __init__(self): self.line = 0
        def __iter__(self): return self
        def next(self):
            self.line += 1
            return FinalizableString("line,{0}".format(self.line))
    
    >>> r = csv.reader(MockFile())
    >>> next(r)
    *** Deleting line,1
    ['line', '1']
    >>> next(r)
    *** Deleting line,2
    ['line', '2']
    

    所以你可以看到csv.reader 不会挂在它从它的迭代器获取的对象上,如果没有其他东西让它们保持活动状态,那么它们会被及时地进行垃圾收集。


    我感觉你没有告诉我们这个问题的更多内容。你能解释一下你为什么担心这个吗?

    【讨论】:

    • emmm,你在上面的代码中“它不会提前读取”是对的,但是我们怎么知道读者在它需要 ['line' 之后确实'hold' ['Line', 1] , 2] ?这是我最关心的问题。
    • 嗨,Gareth,感谢您的更新,我想我现在对此更有信心,我将查看您提到的 c 文件以获取详细信息。我正在尝试编写一个脚本来处理一些大文件,所以我想确保代码不会耗尽所有内存......在我们将数据写回文件之前我做了一些缓冲,但也想确保 csv reader 不会以某种方式“缓存”它加载的数据,否则我的 on-the-fly-with-buffer 将变得毫无意义
    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2019-08-18
    • 2011-07-15
    • 2012-06-24
    • 2012-12-28
    相关资源
    最近更新 更多