Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You've got a few different easily separated goals you're trying to achieve here. First, I'll talk about watching the log file.</p> <p>Your generator has a couple problems. One of them is big - it calls <code>time.sleep(0.1)</code>. The <code>sleep</code> function blocks for the amount of time passed to it. While it is blocking, the thread which called it can't do anything else (that's roughly what "blocking" means, after all). You're iterating over the generator in the same thread as <code>LogProtocol.connectionMade</code> is called in (since <code>connectionMade</code> calls <code>follow</code>). <code>LogProtocol.connectionMade</code> is called in the same thread as the Twisted reactor is running, because Twisted is roughly single threaded.</p> <p>So, you're blocking the reactor with the <code>sleep</code> calls. As long as sleep is blocking the reactor, the reactor can't do anything - like send bytes over sockets. Blocking is transitive, by the way. So <code>LogProtocol.connectionMade</code> is an even bigger problem: it iterates indefinitely, sleeping and reading. So it blocks the reactor indefinitely.</p> <p>You need to read lines from the file without blocking. You can do this by polling - which is effectively the approach you're taking now - but avoiding the sleep call. Use <code>reactor.callLater</code> to schedule future reads from the file:</p> <pre><code>def follow(fObj): line = fObj.readline() reactor.callLater(0.1, follow, fObj) follow(open(filename)) </code></pre> <p>You can also let <code>LoopingCall</code> deal with the part that makes this a loop that runs forever:</p> <pre><code>def follow(fObj): line = fObj.readline() from twisted.internet.task import LoopingCall loop = LoopingCall(follow, open(filename)) loop.start(0.1) </code></pre> <p>Either of these will let you read new lines from the file over time without blocking the reactor. Of course, they both just drop the line on the floor after they read it. This leads me to the second problem...</p> <p>You need to react to the appearance of a new line in the file. Presumably you want to write it out to your connection. This isn't too hard: "reacting" is pretty easy, it usually just means calling a function or a method. In this case, it's easiest to have the <code>LogProtocol</code> set up the log following and supply a callback object to handle lines when they appear. Consider this slight adjustment to the <code>follow</code> function from above:</p> <pre><code>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) </code></pre> <p>Now you can non-blockingly poll a log file for new lines <em>and</em> learn when one has actually shown up. This is simple to integrate with <code>LogProtocol</code>...</p> <pre><code>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) </code></pre> <p>One last detail is that you probably want to stop watching the file when the connection is lost:</p> <pre><code> def connectionLost(self, reason): self.loop.stop() </code></pre> <p>So, this solution avoids blocking by using <code>LoopingCall</code> instead of <code>time.sleep</code> and pushes lines to the protocol when they're found using simple method calls.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload