<h2>@半径</h2>
<p>有几点使我在这方面感到困惑。我意识到我错过了理解的基础:什么是你的问题。</p>
<p>现在我想我已经明白了,请你确认。</p>
<p>我会那样代表你的代码</p>
<pre><code>import itertools
def grouper(iterable, chunksize):
i = iter(iterable)
while True:
chunk = list(itertools.islice(i, int(chunksize)))
if not chunk:
break
yield chunk
............
............
gigi = grouper(an_iterable,4)
# before A
# A = grouper(an_iterable,4)
# corrected:
A = gigi.next()
# after A
................
...........
# deducing an object x from A ; x doesn't consumes a lot of memory
............
# deleting A because it consumes a lot of memory:
del A
# code carries on, taking time to executes
................
................
......
..........
# before B
# B = grouper(an_iterable,4)
# corrected:
B = gigi.next()
# after B
.....................
........
</code></pre>
<p>你的问题是,即使是在<br/>
<strong>#删除后,代码继续执行,需要时间来执行</strong><br/>
以及<br/>
在B之前,<br/>
已删除名称为“A”的对象仍然存在并占用大量内存,因为此对象与生成器函数中的标识符“chunk”之间仍然存在绑定?</p>
<p>请原谅我问你这个显而易见的问题。<br/>
但是,由于一次在线程中出现了某种混乱,我希望您确认我现在已经正确地理解了您的问题。</p>
<p>是的。</p>
<h2>@菲哈格</h2>
<p>你在评论中写道:</p>
<blockquote>
<p>1)<br/>
After the <code>yield chunk</code>, there is no way to access the value
stored in chunk from this function. Therefore, this function does not
hold any references to the object in question</p>
</blockquote>
<p>(顺便说一句,我不会写<em>所以</em>,而是写'because')</p>
<p>我认为这种肯定是有争议的
事实上,我确信这是假的。但是,如果我们也考虑到你在回答的开头所说的话,你的伪装就有微妙之处,不仅仅是在这段引语中,而是在全球范围内。</p>
<p>让我们把东西收拾好。</p>
<p>下面的代码似乎证明了与您的肯定相反,在yield chunk之后,没有办法从这个函数访问chunk中存储的值</p>
<pre><code>import itertools
def grouper(iterable, chunksize):
i = iter(iterable)
chunk = ''
last = ''
while True:
print 'new turn ',id(chunk)
if chunk:
last = chunk[-1]
chunk = list(itertools.islice(i, int(chunksize)))
print 'new chunk ',id(chunk),' len of chunk :',len(chunk)
if not chunk:
break
yield '%s - %s' % (last,' , '.join(chunk))
print 'end of turn',id(chunk),'\n'
for x in grouper(['1','2','3','4','5','6','7','8','9','10','11'],'4'):
print repr(x)
</code></pre>
<p>结果</p>
<pre><code>new turn 10699768
new chunk 18747064 len of chunk : 4
' - 1 , 2 , 3 , 4'
end of turn 18747064
new turn 18747064
new chunk 18777312 len of chunk : 4
'4 - 5 , 6 , 7 , 8'
end of turn 18777312
new turn 18777312
new chunk 18776952 len of chunk : 3
'8 - 9 , 10 , 11'
end of turn 18776952
new turn 18776952
new chunk 18777512 len of chunk : 0
</code></pre>
<p>是的。</p>
<p>不过,你也写了(这是你答案的开始):</p>
<blockquote>
<p>2)<br/>
After <code>yield chunk</code>, the variable value is never used again in
the function, so a good interpreter/garbage collector will already
free chunk for garbage collection (note: cpython 2.7 seems not do
this, pypy 1.6 with default gc does).</p>
</blockquote>
<p>这一次,您不会说函数在<code>yield chunk</code>之后不再持有<strong>chunk</strong>的引用,而是说在<code>while</code>循环的下一轮中更新<strong>chunk</strong>之前,它的值再次是<strong>未使用。没错,在Radim的代码中,在下一轮循环中,在指令<code>chunk = list(itertools.islice(i, int(chunksize)))</code>中重新分配标识符“chunk”之前,对象“chunk”不会再次使用。</p>
<p>是的。</p>
<p>这段引文中的肯定2不同于前面的肯定1,有两个逻辑结果:</p>
<p><strong>首先,我上面的代码无法向像您这样的人严格证明,在<code>yield chunk</code>指令之后确实有方法访问chunk的值。<br/>
因为我上面代码中的条件与您确认相反的条件不同,也就是说:在您所说的Radim代码中,对象<strong>chunk</strong>在下一回合之前确实没有再次使用。<br/>
然后,我们可以假设这是因为在我上面的代码中使用了<strong>chunk</strong>(指令<code>print 'end of turn',id(chunk),'\n'</code>、<code>print 'new turn ',id(chunk)</code>和<code>last = chunk[-1]</code>确实使用了它),在<code>yield chunk</code>之后,对对象<strong>chunk</strong>的引用仍然保持。</p>
<p><strong>其次,进一步推理,收集您的两个引文,得出结论,您认为这是因为在Radim代码中的<code>yield chunk</code>指令之后,<strong>chunk</strong>不再使用,因此没有对它进行任何引用。<br/>
这是一个逻辑问题,IMO:没有对对象的引用是其释放的条件,因此如果你假装内存是从对象中释放的,因为它不再被使用,这相当于假设内存从对象中释放出来,因为它的失业使得interpreter在函数中删除对它的引用。</p>
<p>我总结:<br/>
假设在Radim的代码中,<strong>chunk</strong>在<code>yield chunk</code>之后不再使用,那么对它的引用就不再是hold,然后。。。。。cpython 2.7不会这么做。。。但是pypy 1.6使用默认的gc从对象块中释放内存。</p>
<p>在这一点上,我对这个结果的原因感到非常惊讶:这是因为rong>chunk</strong>不再使用pypy 1.6来释放它。你并没有清楚地表达出这种推理,但没有它,我会发现你在这两个引文中所说的是不合逻辑和不可理解的。</p>
<p>令我困惑的是,这一结论以及我不同意这一切的原因是,它意味着pypy 1.6能够分析代码并检测出在<code>yield chunk</code>之后,<strong>块</strong>不会被再次使用。我觉得这个想法完全难以置信,我希望你:</p>
<ul>
<li><p>来解释你到底是怎么想的。我理解你的想法错在哪里?</p></li>
<li><p>如果你有证据表明,至少pypy 1.6在不再使用时不包含对<strong>块的引用。<br/>
Radim的初始代码的问题是,由于对象的引用仍然保留在生成器函数中,因此对象的持久性消耗了太多内存:这是存在这样一个持久性引用的间接症状。<br/>
你观察过Pypy1.6的类似行为吗?我看不出另一种方法来证明生成器中剩余的引用,因为根据您的引用2,在<code>yield chunk</code>之后使用<strong>chunk</strong>就足以触发对它的引用。这是一个类似于量子力学的问题:测量一个粒子的速度会改变它的速度。。。。。</p></li>
</ul>