<h2>注:</h2>
<ol>
<li>您的<code>get('/foo', 1)</code>是匿名生成器对象,<code>Task(get('/foo', 1))</code>是匿名<code>Task</code>对象。在</li>
<li>GC是python垃圾收集/收集器的缩写</li>
</ol>
<h2>原始代码的引用链是:</h2>
<pre><code>selector > # socket_fd
anonymous Task(get('/foo', 1)) > anonymous get('/foo', 1) > s
</code></pre>
<p>因此,匿名<code>Task(get('/foo', 1))</code>对象一完成就被GC收集。这是因为:</p>
<blockquote>
<p>Python GC will collect the memory of an object as soon as it finds the object's reference count == 0. But python GC is not running as a thread so maybe not the moment right after the object's reference count decreases to 0.</p>
</blockquote>
<p>那么匿名的<code>get('/foo', 1)</code>将被收集,然后是{<cd6>}。在这里,<code>s</code>被收集、关闭,其对应的套接字fd编号(在您的示例中是#368)已被释放。在</p>
<p>但是套接字fd号(#368)已注册到<code>selector</code>。在</p>
<p>然后运行<code>Task(get('/bar',2))</code>,一个新的<code>socket s</code>试图申请一个“新”fd,因为#368是可用的(只要系统中的其他进程没有声明它),您将得到#368作为套接字fd。在</p>
<h2>在中取消注释<code>arr.append(self.__init__)</code>任务.步骤()</h2>
<p>在中取消注释<code>arr.append(self.__init__)</code>后任务.步骤()方法,全局<code>arr</code>包含对<code>Task(get('/foo', 1))</code>的引用。那么<code>Task(get('/foo', 1))</code>引用了<code>get('/foo', 1)</code>。然后<code>get('/foo', 1)</code>引用了本地套接字<code>s</code>。该参考链如下:</p>
^{pr2}$
<p><code>arr</code>通过您的程序是有效的,因此<code>s</code>将不会被GC收集。后面的<code>s = socket.socket()</code>将不会得到相同的<code>fd</code>,因为它仍然由{<cd6>}持有。在</p>
<h2>使用<code>s</code>代替<code>s.fileno()</code></h2>
<p>如果使用<code>selector.register(s ..)</code>而不是<code>selector.register(s.fileno()..)</code>,全局<code>selector</code>将保存对本地<code>s</code>的引用,引用链是:</p>
<pre><code>selector > s
</code></pre>
<p>虽然这两个匿名对象已经不存在,但是您的<code>get('/foo', 1))::s</code>和{<cd31>}仍然由全局<code>selector</code>持有。所以不要担心这两个<code>fd</code>不会碰撞。在</p>
<h2>循环参考?在</h2>
<p>答案是否定的。你的情况与循环引用无关。在</p>
<h2>在收集gc?在</h2>
<p>好吧,用<code>time.sleep(0.02)</code>代替它,你会观察到同样的现象。这可能是由于:</p>
<ol>
<li>套接字来了,套接字去了,由系统的其他进程驱动。在</li>
<li>python GC线程可能需要一些时间,直到它“找到”应该被收集的<code>s</code>,或者线程正在收集。在</li>
</ol>