Python Twisted Deferred: требуется уточнение - PullRequest
2 голосов
/ 15 января 2012

Я надеюсь получить некоторые разъяснения о лучшем способе обработки «первого» * ​​1001 * deferreds , т. Е. Не просто добавлении обратных вызовов и ошибок в существующие методы Twisted, которые возвращают отложенный, но лучший способ созданияэти original deferreds.

В качестве конкретного примера, здесь представлены 2 варианта одного и того же метода: он просто подсчитывает количество строк в некоторых довольно больших текстовых файлах и используется как начальная точка для цепочки отсрочек.

Метод 1: Этот вариант не очень хорош, так как отсрочка запускается непосредственно методом реактором.callLater.

def get_line_count(self):
    deferred = defer.Deferred()

    def count_lines(result):
        try:
            print_file = file(self.print_file_path, "r")
            self.line_count = sum(1 for line in print_file)
            print_file.close()
            return self.line_count
        except Exception as inst:
            raise InvalidFile()

     deferred.addCallback(count_lines)
     reactor.callLater(1, deferred.callback, None)
     return deferred

Метод 2: немного лучше, так как отсроченный фактически срабатывает , когда результат доступен

def get_line_count(self):
    deferred = defer.Deferred()

    def count_lines():
        try:
            print_file = file(self.print_file_path, "r")
            self.line_count = sum(1 for line in print_file)
            print_file.close()
            deferred.callback(self.line_count)
        except Exception as inst:
            deferred.errback(InvalidFile())

    reactor.callLater(1, count_lines)
    return deferred

Примечание: Вы могли бы также указать, что оба они на самом деле являются синхронными и потенциально блокирующими методами (и я, возможно, мог бы использовать « MaybeDeferred »?).Но хорошо, что это на самом деле один из аспектов, которые меня смущают.

  1. Для Метод 2 , если метод count_lines оченьмедленно (считая строки в некоторых огромных файлах и т. д.), может ли оно «заблокировать» все приложение Twisted?Я прочитал довольно много документации о том, как обратные вызовы и ошибочные действия и реактор ведут себя вместе (обратные вызовы должны выполняться быстро или возвращать отложенные ответы и т. Д.), Но в этом случае я просто не вижу и буду очень признателен за некоторые указатели /примеры и т. д.

  2. Существуют ли какие-нибудь статьи / понятные пояснения, касающиеся наилучшего подхода к созданию этих «первых» отсрочек?Я прочитал эти прекрасные статьи , и они очень помогли с некоторым базовым пониманием, но я все еще чувствую, что мне не хватает части.

  3. Для кода блокировки , будет ли это типичным случаем для DeferToThread или реактор. Spawnprocess ?Я прочитал много вопросов, таких как , этот и , эта статья , но я все еще не уверен на 100%, как бороться с потенциально блокирующим кодом, в основном при работе с файлом i /o

Извините, если что-то кажется слишком простым, но я действительно хочу научиться использовать Twisted более тщательно.(Это был действительно мощный инструмент для всех сетевых аспектов).Спасибо за ваше время!

1 Ответ

2 голосов
/ 15 января 2012

Да, вы правильно поняли: вам нужны потоки или отдельные процессы, чтобы избежать блокировки цикла событий Twisted.Использование Deferreds волшебным образом не сделает ваш код неблокирующим.Для ваших вопросов:

  1. Да, вы заблокируете цикл обработки событий, если count_lines очень медленный.Отсрочка к потоку решит эту проблему.

  2. Я использовал Документация по Twisteds , чтобы узнать, как работают Deferreds, но я думаю, вы уже прошли через это.Статья о поддержке 1011 * базы данных была полезной, поскольку в ней четко сказано, что эта библиотека построена с использованием потоков.Это способ преодоления синхронно-асинхронного разрыва.

  3. Если вызов действительно блокирует, вам нужно DeferToThread.Сам Python является своего рода однопоточным, что означает, что только один поток может одновременно выполнять байт-код Python.Однако, если созданный вами поток в любом случае заблокирует ввод-вывод, тогда эта модель работает нормально: поток снимет глобальную блокировку интерпретатора и, таким образом, позволит запускать другие потоки Python, включая основной поток с циклом событий Twisted.

    Это также может быть случай, когда вы можете использовать неблокирующий ввод / вывод в вашем коде.Это можно сделать, например, с помощью модуля select.В этом случае вам не нужен отдельный поток.Twisted использует эту технику для внутреннего использования, и вам не нужно об этом думать, если вы выполняете обычный сетевой ввод-вывод.Но если вы делаете что-то экзотическое, тогда хорошо знать, как все устроено так, чтобы вы могли делать то же самое.

Надеюсь, это немного прояснит ситуацию!

...