使用产量的函数有多少内存?

时间:2015-09-07 20:48:02

标签: python memory generator yield

我无法理解yield关键字 我理解程序执行时会发生什么影响,但我不太了解它使用了多少内存。

我会尝试用例子来解释我的怀疑 我们假设我们有三个功能:

HUGE_NUMBER = 9223372036854775807

def function1():
    for i in range(0, HUGE_NUMBER):
        yield i

def function2():
    x = range(0, HUGE_NUMBER)
    for i in x:
        yield i

def function3(file):
    with open(file, 'r') as f:
        dictionary = dict(csv.reader(f, delimiter = ' '))
    for k,v in dictionary.iteritems():
        yield k,v

如果我迭代第一个函数返回的生成器,那么巨大的范围是否实际存储在内存中?

第二个功能怎么样?

如果我迭代第三个函数返回的生成器,那么我的程序是否会使用更少的内存(而不是仅仅创建该字典并直接迭代它)?

3 个答案:

答案 0 :(得分:5)

Python 2 range()函数生成的巨大列表需要存储,是的,并且会在生成器函数的整个生命周期内占用内存。

生成器函数可以内存有效,前提是它生成的结果是根据需要计算的,但range()函数会预先生成所有结果。< / p>

你可以计算下一个数字:

def function1():
    i = 0
    while i < HUGE_NUMBER:
        yield i
        i += 1

并且您得到的结果相同,但您不会一次性存储整个范围内的所有数字。这基本上就是xrange() object的循环;它根据要求计算数字。 (在Python 3中xrange()替换了range())。

同样适用于您的function3;您首先将整个文件读入字典,以便在迭代时仍然存储在内存中。之后不需要将整个文件读入内存中以生成每个元素。您可以循环遍历文件并生成行:

def function3(file):
    seen = set()
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        for k, v in reader:
            if k in seen:
                # already seen
                continue
            seen.add(k)
            yield k, v

这只存储了可以避免重复的密钥(就像字典一样),但是没有存储这些值。迭代生成器时内存会增加。如果重复项不是问题,您可以省略完全跟踪看到的键:

def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        for k, v in reader:
            yield k, v

甚至

def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        return reader

毕竟读者是可迭代的。

答案 1 :(得分:0)

生成器对象包含对函数范围的引用,以及对其中所有本地对象的扩展。减少内存使用的方法是在每个级别使用迭代器,而不仅仅是在顶层。

答案 2 :(得分:-1)

如果要检查对象使用了多少内存,可以遵循this post作为代理。我发现它很有帮助。

“尝试一下:

sys.getsizeof(object)

getsizeof()调用对象的 sizeof 方法,如果该对象由垃圾收集器管理,则会添加额外的垃圾收集器开销。”

A recursive recipe