У вас есть несколько разных легко разделяемых целей, которые вы пытаетесь достичь здесь.Сначала я расскажу о просмотре файла журнала.
У вашего генератора пара проблем.Один из них большой - он звонит time.sleep(0.1)
.Функциональные блоки sleep
для количества времени, переданного ему.Пока он блокирует, вызывающий его поток больше ничего не может сделать (это примерно то, что означает «блокировка», в конце концов).Вы перебираете генератор в том же потоке, в котором вызывается LogProtocol.connectionMade
(так как connectionMade
вызывает follow
).LogProtocol.connectionMade
вызывается в том же потоке, в котором работает Twisted реактор, потому что Twisted является примерно однопоточным.
Итак, вы блокируете реактор с помощью вызовов sleep
.Пока сон блокирует реактор, реактор ничего не может сделать - например, отправить байты через сокеты.Кстати, блокировка транзитивна.Так что LogProtocol.connectionMade
- еще большая проблема: она повторяется бесконечно, спит и читает.Таким образом, он блокирует реактор на неопределенный срок.
Вам нужно читать строки из файла без блокировки.Вы можете сделать это путем опроса - который фактически является подходом, который вы используете сейчас - но избегая вызова в спящем режиме.Используйте reactor.callLater
для планирования будущих чтений из файла:
def follow(fObj):
line = fObj.readline()
reactor.callLater(0.1, follow, fObj)
follow(open(filename))
Вы также можете разрешить LoopingCall
обработать часть, которая делает этот цикл, который выполняется вечно:
def follow(fObj):
line = fObj.readline()
from twisted.internet.task import LoopingCall
loop = LoopingCall(follow, open(filename))
loop.start(0.1)
Любой из них позволит вам читать новые строки из файла с течением времени, не блокируя реактор.Конечно, они оба просто бросают линию на пол после того, как прочитают это.Это приводит меня ко второй проблеме ...
Вам нужно реагировать на появление новой строки в файле.Предположительно, вы хотите записать это в вашу связь.Это не так сложно: «реагировать» довольно просто, обычно это просто вызов функции или метода.В этом случае проще всего LogProtocol
настроить последующий журнал и предоставить объект обратного вызова для обработки строк при их появлении.Рассмотрим эту небольшую корректировку функции follow
сверху:
def follow(fObj, gotLine):
line = fObj.readline()
if line:
gotLine(line)
def printLine(line):
print line
loop = LoopingCall(follow, open(filename), printLine)
loop.start(0.1)
Теперь вы можете без блокировки опросить файл журнала для новых строк и узнать, когда он действительно появился.Это просто для интеграции с LogProtocol
...
class LogProtocol(Protocol):
def connectionMade(self):
self.loop = LoopingCall(follow, open(filename), self._sendLogLine)
self.loop.start()
def _sendLogLine(self, line):
self.transport.write(line)
Еще одна деталь: вы, вероятно, захотите прекратить просмотр файла при потере соединения:
def connectionLost(self, reason):
self.loop.stop()
Это решение позволяет избежать блокировки с помощью LoopingCall
вместо time.sleep
и передает строки в протокол, когда они обнаруживаются с помощью простых вызовов методов.