我试图找出task.LoopingCall和Twisted中的reactor.callInThread之间的差异。
我在LoopingCall中的所有self.sendLine都会立即执行。 callInThread中的那些不是。它们只是在LoopingCall中的那个完成之后发送的。即使我发送了正确的分隔符。
为什么?有什么不同?他们不是两个线程吗?
这是服务器:
from twisted.internet import reactor, protocol, task
from twisted.protocols import basic
from twisted.python import log
import sys
import time
import threading
import Queue
class ServerProtocol(basic.LineOnlyReceiver):
delimiter = '\0'
clientReady = 1
def __init__(self):
print 'New client has logged on. Waiting for initialization'
def lineReceived(self, line):
if line.startswith('I'):
print 'Data started with I: '+line
user = dict(uid=line[1:6], x=line[6:9], y=line[9:12])
self.factory.users[user['uid']] = user
log.msg(repr(self.factory.users))
self.startUpdateClient(user)
reactor.callInThread(self.transferToClient)
self.sendLine(user['uid'] + ' - Beginning - Initialized')
print user['uid'] + ' - Beginning - Initialized'
elif line.startswith('P'):
print 'Ping!'
elif line[0:3] == 'ACK':
print 'Received ACK'
self.clientReady = 1
#else:
#self.transport.loseConnection()
def _updateClient(self, user):
if self._running == 0:
self._looper.stop()
return
self._running -= 1
self._test += 1
print user['uid'] + ' Sending test data' + str(self._test)
self.sendLine(user['uid'] + ' Test Queue Data #%d' % (self._test,) + '\0')
def startUpdateClient(self, user):
self._running, self._test = 25, 0
self._looper = task.LoopingCall(self._updateClient, user)
self._looper.start(1, now=False)
print user['uid'] + ' - Startupdateclient'
def transferToClient(self):
test = 20
while test > 0:
if self.clientReady == 1:
test = test-1
print 'Reactor test ' + str(test) + ' - ' + str(time.time())
self.clientReady = 0
self.sendLine('This is reactortest ' + str(test) + ' - ' + str(time.time()) +' \0')
class Server(protocol.ServerFactory):
protocol = ServerProtocol
def __init__(self):
self.users = {}
if __name__ == '__main__':
log.startLogging(sys.stderr)
reactor.listenTCP(2000, Server())
reactor.run()
这是客户:
#!/usr/bin/env python
import socket
import time
host = 'localhost'
port = 2000
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send('I12345070060\0')
running = 1
while running:
s.send('ACK\0')
data = s.recv(size)
if data:
print 'Received:', data
else:
print 'Closing'
s.close()
running=0
答案 0 :(得分:4)
为什么?有什么不同?他们不是两个线程吗?
没有。 LoopingCall
使用callLater
;它在反应堆中运行呼叫。
是的,他们应该如此。我在LoopingCall中的所有self.sendLine都会立即执行。
callInThread中的那些不是。
并不是因为它们没有被执行,而是因为你从一个线程调用了一个反应堆API,而你从来没有这样做过,你已经将你的程序放入了状态一切都完全被打破,永远。每个未来的API调用都可能产生奇怪的,破碎的结果,或者没有结果,或者随机的,无法解释的崩溃。
你知道,多线程程序的正常工作方式; - )。
要重复:除了callFromThread
(以及调用callFromThread
的扩展内容,如blockingCallFromThread
)之外,每个API都是扭曲的,不是线程安全的< / em>的。不幸的是,为每个API添加警告都是代码维护的噩梦,因此有几个用户通过调用API并注意到一些奇怪的东西,以与您相同的方式发现了这种约束。
如果您有一些代码在需要调用reactor API的线程中运行,请使用callFromThread
或blockingCallFromThread
,它会将调用分派给reactor线程,其中一切都应该顺利进行。但是,对于像定时调用这样的东西,根本不需要使用线程,它们会不必要地使你的程序复杂化。
答案 1 :(得分:1)
你看过LoopingCall
的{{3}}了吗?没有线程涉及 - 它在主线程上运行(每秒一次,就像你调用它的start
方法一样),即通常是反应器的线程。 docs是导致函数在单独线程上运行的两个中唯一的一个。