У меня есть кусок кода Python для практики совместных процедур Python. Как объяснил А. Джесси Джирю Дэвис.
- Во-первых, я определяю сопрограмму с именем 'get' для получения содержимого некоторого URL-адреса.
- Затем я определяю класс Task для итерации сопрограммы до завершения.
- Затем я создаю две Task, которые открывают два разных URL.
Но я получил сообщение об ошибке: KeyError: '368 (FD 368) уже зарегистрирован' в строке selector.register(s.fileno(), EVENT_WRITE).
Эта ошибка вызвана тем, что два вызова socket.socket() возвращают один и тот же файловый дескриптор. На самом деле, этот файловый дескриптор 368 был выделен в предыдущем вызове, но все еще возвращен во втором вызове.
- Затем я добавляю выражение, которое изменяет внешнюю переменную.
На этот раз сообщение об ошибке просто исчезло! Если вы хотите запустить код самостоятельно, вы можете раскомментировать arr.append(self.init) в методе Task.step, чтобы увидеть вывод без ошибок.
EDIT Если я явно вызову сборку мусора Python, иногда эта ошибка исчезнет. Но ПОЧЕМУ время от времени?
После нескольких дней поиска и чтения документов по Python я до сих пор не понимаю, почему это происходит. Я только что пропустил некоторые «питоновские ошибки», не так ли?
Я использую python 3.6 для тестирования. Код выглядит следующим образом, и я удалил весь ненужный код, чтобы сделать следующий код точным и соответствующим теме:
#! /usr/bin/python
from selectors import DefaultSelector, EVENT_WRITE
import socket
import gc
selector = DefaultSelector()
arr = [1, 2, 3]
class Task:
def __init__(self, gen):
self.gen = gen
self.step()
def step(self):
next(self.gen)
# arr.append(self.__init__)
def get(path, count = 0):
s = socket.socket()
print(count, 'fileno:', s.fileno())
s.connect(('www.baidu.com', 80))
selector.register(s.fileno(), EVENT_WRITE)
yield
Task(get('/foo',1))
gc.collect()
Task(get('/bar',2))
Task()
->self.step
->object
->Task()
. Вы создали циклическую ссылку, и один из этих объектов имеет ссылку на генератор, поэтому он будет очищен только при следующем запуске сборщика мусора. Что делает ошибку недетерминированной. - person dhke   schedule 20.10.2017object.append(self.__init__)
на месте. Это связано с тем, что консервативная очистка на основе подсчета ссылок работает только при отсутствии циклических ссылок. - person dhke   schedule 20.10.2017selector.register(s, EVENT_WRITE)
должно решить вашу проблему. В этом случаеselector
содержит ссылку на объект сокета. - person dhke   schedule 20.10.2017