У нас есть сетевой клиент на основе asyncore с сетевым подключением пользователя, воплощенным в файле Dispatcher
. Цель состоит в том, чтобы пользователь, работающий с интерактивного терминала, мог вводить команды сетевого запроса, которые отправлялись бы на сервер и в конечном итоге возвращались с ответом. Клиент написан как асинхронный, поэтому пользователь может запускать несколько запросов на разных серверах одновременно, собирая результаты по мере их появления.
Как мы можем позволить пользователю вводить команды, пока мы идем по циклу выбора? Если мы нажмем вызов select()
, зарегистрированный только как доступный для чтения, то мы будем сидеть там, пока не прочитаем данные или тайм-аут. В течение этого (возможно, очень долгого) времени пользовательский ввод будет игнорироваться. Если вместо этого мы всегда регистрируемся как доступные для записи, мы получаем горячую петлю.
Одно из плохих решений выглядит следующим образом. Мы запускаем цикл выбора в отдельном потоке и заставляем пользователя вводить входные данные в потокобезопасную очередь записи, вызывая метод, который мы определили в нашем Dispatcher. Что-то типа
def myConnection.enqueue(self, someData):
self.lock.acquire()
self.queue.put(someData)
self.lock.release()
Затем мы регистрируемся как доступные для записи только в том случае, если очередь не пуста.
def writable(self):
return not self.queue.is_empty()
Затем мы указываем тайм-аут для select()
, который короток по человеческим меркам, но велик для компьютера. Таким образом, если мы находимся в вызове select
, зарегистрированном только для чтения, когда пользователь вводит новые данные, цикл в конечном итоге снова запустится и обнаружит, что есть новые данные для записи. Однако это плохое решение, потому что мы могли бы захотеть использовать этот код и для клиентских соединений серверов, и в этом случае мы не хотим, чтобы время простоя, которое вы получаете, ждало select()
истечения времени ожидания. Опять же, я понимаю, что это плохое решение.
Кажется, что правильным решением было бы ввести пользовательский ввод через дескриптор файла, чтобы мы могли обнаруживать новый ввод, находясь в вызове select
, зарегистрированном только как доступный для чтения. Есть ли способ сделать это?
ПРИМЕЧАНИЕ. Это попытка упростить вопрос опубликовано здесь