• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

python3使用迭代生成器实现减少内存占用

python 搞代码 4年前 (2022-01-07) 31次浏览 已收录 0个评论

这篇文章主要介绍了python3使用迭代生成器实现减少内存占用的相关资料,需要的朋友可以参考下

技术背景

在python编码中for循环处理任务时,会将所有的待遍历参量加载到内存中。其实这本没有必要,因为这些参量很有可能是一次性使用的,甚至很多场景下这些参量是不需要同时存储在内存中的,这时候就会用到本文所介绍的迭代生成器yield。

基本使用

首先我们用一个例子来演示一下迭代生成器yield的基本使用方法,这个例子的作用是构造一个函数用于生成一个平方数组。在普通的场景中我们一般会直接构造一个空的列表,然后将每一个计算结果填充到列表中,最后return列表即可,对应的是这里的函数square_number。而另外一个函数square_number_yield则是为了演示yield而构造的函数,其使用语法跟return是一样的,不同的是每次只会返回一个值:

 # test_yield.py def square_number(length): s = [] for i in range(length): s.append(i ** 2) return s def square_number_yield(length): for i in range(length): yield i ** 2 if __name__ == '__main__': length = 10 sn1 = square_number(length) sn2 = square_number_yield(length) for i in range(length): print (sn1[i], '\t', end='') print (next(sn2)) 

在main函数中我们对比了两种方法执行的结果,打印在同一行上面,用end=”指令可以替代行末的换行符号,具体执行的结果如下所示:

 [dechin@dechin-manjaro yield]$ python3 test_yield.py 0       0 1       1 4       4 9       9 16      16 25      25 36      36 49      49 64      64 81      81 

可以看到两种方法打印出来的结果是一样的。也许有些场景下就是需要持久化的存储函数中返回的结果,这一点用yield也是可以实现的,可以参考如下示例:

 # test_yield.py def square_number(length): s = [] for i in range(length): s.append(i ** 2) return s def square_number_yield(length): for i in range(length): yield i ** 2 if __name__ == '__main__': length = 10 sn1 = square_number(length) sn2 = square_number_yield(length) sn3 = list(square_number_yield(length)) for i in range(length): print (sn1[i], '\t', end='') print (next(sn2), '\t', end='') print (sn3[i]) 

这里使用的方法是直接将yield生成的对象转化成list格式,或者用sn3 = [i for i in square_number_yield(length)]这种写法也是可以的,在性能上应该差异不大。上述代码的执行结果如下:

 [dechin@dechin-manjaro yield]$ python3 test_yield.py 0       0       0 1       1       1 4       4       4 9       9       9 16      16      16 25      25      25 36      36      36 49      49      49 64      64      64 81      81      81 

进阶测试

在前面的章节中我们提到,使用yield可以节省程序的内存占用,这里我们来测试一个100000大小的随机数组的平方和计算。如果使用正常的逻辑,那么写出来的程序就是如下所示(关于python内存占用的追踪方法,可以参考这一篇博客):

 # square_sum.py import tracemalloc import time import numpy as np tracemalloc.start() start_time = time.time() ss_list = np.random.randn(100000) s = 0 for ss in ss_list: s += ss ** 2 end_time = time.time() print ('Time cost is: {}s'.format(end_time - start_time)) snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats[:5]: print (stat) 

这个程序一方面通过time来测试执行的时间,另一方面利用tracemalloc追踪程序的内存变化。这里是先用np.random.randn()直接产生了100000个随机数的数组用于计算,那么自然在计算的过程中需要存储这些生成的随机数,就会占用这么多的内存空间。如果使用yield的方法,每次只产生一个用于计算的随机数,并且按照上一个章节中的用法,这个迭代生成的随机数也是可以转化为一个完整的list的:

 # yield_square_sum.py import tracemalloc import time import numpy as np tracemalloc.start() start_time = time.time() def ss_list(length): for i in ra<span style="color:transparent">来源gaodai#ma#com搞*!代#%^码网</span>nge(length): yield np.random.random() s = 0 ss = ss_list(100000) for i in range(100000): s += next(ss) ** 2 end_time = time.time() print ('Time cost is: {}s'.format(end_time - start_time)) snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats[:5]: print (stat) 

这两个示例的执行结果如下,可以放在一起进行对比:

 [dechin@dechin-manjaro yield]$ python3 square_sum.py Time cost is: 0.24723434448242188s square_sum.py:9: size=781 KiB, count=2, average=391 KiB square_sum.py:12: size=24 B, count=1, average=24 B square_sum.py:11: size=24 B, count=1, average=24 B [dechin@dechin-manjaro yield]$ python3 yield_square_sum.py Time cost is: 0.23023390769958496s yield_square_sum.py:9: size=136 B, count=1, average=136 B yield_square_sum.py:14: size=112 B, count=1, average=112 B yield_square_sum.py:11: size=79 B, count=2, average=40 B yield_square_sum.py:10: size=76 B, count=2, average=38 B yield_square_sum.py:15: size=28 B, count=1, average=28 B 

经过比较我们发现,两种方法的计算时间是几乎差不多的,但是在内存占用上yield有着明显的优势。当然,也许这个例子并不是非常的恰当,但是本文主要还是介绍yield的使用方法及其应用场景。

无限长迭代器

在参考链接1中提到了一种用法是无限长的迭代器,比如按顺序返回所有的素数,那么此时我们如果用return来返回所有的元素并存储到一个列表里面,就是一个非常不经济的办法,所以可以使用yield来迭代生成,参考链接1中的源代码如下所示:

 def get_primes(number): while True: if is_prime(number): yield number number += 1 

那么类似的,这里我们用while True可以展示一个简单的案例――返回所有的偶数:

 # yield_iter.py def yield_range2(i): while True: yield i i += 2 iter = yield_range2(0) for i in range(10): print (next(iter)) 

因为这里我们限制了长度是10,所以最终会返回10个偶数:

[dechin@dechin-manjaro yield]$ python3 yield_iter.py

总结概要

本文介绍了python的迭代器yield,其实关于yield,我们可以简单的将其理解为单个元素的return。这样不仅就初步理解了yield的使用语法,也能够大概了解到yield的优势,也就是在计算过程中每次只占用一个元素的内存,而不需要一直存储大量的元素在内存中。

到此这篇关于python3使用迭代生成器实现减少内存占用的文章就介绍到这了,更多相关python3实现减少内存占用内容请搜索gaodaima搞代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持gaodaima搞代码网

以上就是python3使用迭代生成器实现减少内存占用的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:python3使用迭代生成器实现减少内存占用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址