Ответ 1
Нет чистого ответа. Есть несколько уродливых.
Вначале я выдвигал отвергнутые идеи в вопросе. Поскольку стало ясно, что нет правильных ответов, я решил опубликовать различные субоптимальные альтернативы в качестве ответа на список. Некоторые из них вдохновлены комментариями, спасибо.
Поддержка библиотеки
Идеальное решение было бы, если OpenerDirector
предложил оператор отмены.
Это не так. Авторы библиотек отмечают: если вы обеспечиваете длительные медленные операции, вам нужно предоставить способ их отмены, если люди будут использовать их в реальных приложениях.
Уменьшить время ожидания
Как общее решение для других, это может сработать. При меньшем тайм-ауте он будет более восприимчивым к изменениям обстоятельств. Однако это также приведет к сбою загрузки, если они не были полностью завершены в тайм-аут, поэтому это компромисс. В моей ситуации это несостоятельно.
Прочитайте загрузку в кусках.
Опять же, как общее решение, это может сработать. Если загрузка состоит из очень больших файлов, вы можете читать их в небольших кусках и прервать после чтения фрагмента.
К сожалению, если (как и в моем случае) задержка заключается в получении первого байта, а не в размере файла, это не поможет.
Убить весь поток.
В то время как есть некоторые агрессивные методы для уничтожения потоков, в зависимости от операционной системы они не рекомендуются. В частности, они могут привести к возникновению взаимоблокировок. См. Eli Bendersky два статьи (через @JBernardo).
Просто не отвечайте
Если операция прерывания была инициирована пользователем, может быть проще просто не отвечать на запросы и не действовать по запросу до завершения открытой операции.
Является ли эта неприкосновенность приемлемой для ваших пользователей (подсказка: нет!), зависит от вашего проекта.
Он также продолжает размещать запрос на сервере, даже если результат известен как ненужный.
Позволяет переходить в другой поток.
Если вы создаете отдельный поток для запуска операции, а затем обмениваетесь этим потоком прерывистым способом, вы можете отказаться от заблокированного потока и начать работу над следующей операцией. В конце концов, поток будет разблокирован, а затем он может изящно отключиться.
Поток должен быть демоном, поэтому он не блокирует полное закрытие приложения.
Это даст пользователю отзывчивость, но это означает, что сервер должен будет продолжать поддерживать его, даже если результат не нужен.
Перепишите методы сокетов на основе опроса.
Как описано в @Luke answer, может быть возможно предоставить (хрупкие?, unportable?) расширения в стандартные библиотеки Python.
Его решение изменяет операции сокета от блокировки до опроса. Другой может позволить завершить работу с помощью метода socket.shutdown()
(если это действительно приведет к прерыванию заблокированного сокета - не проверено.)
Решение на основе Twisted может быть более чистым. См. Ниже.
Замените сокеты асинхронными, не потоковыми библиотеками.
Twisted framework предоставляет заменяемый набор библиотек для сетевых операций, управляемых событиями. Я понимаю, это означает, что все разные коммуникации могут обрабатываться одним потоком без блокировки.
Саботаж
Возможно, можно перемещаться по OpenerDirector
, чтобы найти блокировку базового уровня, которая блокирует, и саботировать ее напрямую (будет ли socket.shutdown()
достаточным?), чтобы вернуть ее.
Тьфу.
Поместите его в отдельный (убивающий) процесс
Поток, который считывает сокет, может быть перенесен в отдельный процесс, и для передачи результата может использоваться межпроцессная связь. Этот IPC может быть прерван раньше клиентом, а затем весь процесс может быть убит.
Попросите веб-сервер отменить
Если вы контролируете считываемый веб-сервер, ему может быть отправлено отдельное сообщение с просьбой закрыть сокет. Это должно заставить заблокированный клиент реагировать.