I just ran in the following behavior. I can reproduce it most of the time
by running (in the asyncio repo)
python3 -m examples.crawl -q xkcd.com
and hitting ^C after letting it run for a few seconds. I then get many
tracebacks like this:
Exception ignored in: <generator object fetch at 0x10e7f23a8>
Traceback (most recent call last):
File "/Users/guido/tulip/examples/crawl.py", line 777, in fetch
yield from fetcher.fetch() # Fetcher gonna fetch.
File "/Users/guido/tulip/examples/crawl.py", line 526, in fetch
self.request.close()
File "/Users/guido/tulip/examples/crawl.py", line 322, in close
self.conn.close(recycle)
File "/Users/guido/tulip/examples/crawl.py", line 274, in close
self.writer.close()
File "/Users/guido/tulip/asyncio/streams.py", line 263, in close
return self._transport.close()
File "/Users/guido/tulip/asyncio/selector_events.py", line 375, in close
self._loop.remove_reader(self._sock_fd)
File "/Users/guido/tulip/asyncio/selector_events.py", line 155, in
remove_reader
key = self._selector.get_key(fd)
AttributeError: 'NoneType' object has no attribute 'get_key'
Using pdb it *appears* that the line at the top of the traceback is
executed "sponetaneously", but in fact I think what is happening is the
following: main() has a try/finally that closes the event loop; when this
happens there are still many suspended coroutines, and eventually (due to
GC closing the generators) their finally clauses are executed, which end up
calling close() on the stream writer.
I don't like the spurious tracebacks, so I'd like to get rid of them. I
could either set some global flag in my app indicating that the loop has
been closed, or I can fix asyncio so that it will silently ignore the
remove_reader() calls (and remove_writer() too, of course). (I must close
the loop since that's required to avoid crashes on Windows.)
What's the better strategy? Is this the app's responsibility or asyncio's?
--
--Guido van Rossum (python.org/~guido)