ske*_*rit 1 python sockets multithreading twisted
我试图找出 Twisted 中的 task.LoopingCall 和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()
Run Code Online (Sandbox Code Playgroud)
这是客户:
#!/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
Run Code Online (Sandbox Code Playgroud)
这是为什么?有什么不同?它们不都是线程吗?
编号 LoopingCall用途callLater;它在反应器中运行调用。
LoopingCall 中的所有 self.sendLine 都会立即执行。
是的,他们应该如此。
callInThread 中的则不是。
并不是说它们没有被执行,而是因为你从一个线程调用了一个reactor API,而你永远不允许这样做,你已经将你的程序置于一切都完全崩溃的状态,永远。未来的每个 API 调用都可能会产生奇怪的、损坏的结果,或者没有结果,或者随机的、莫名其妙的崩溃。
您知道,多线程程序的正常工作方式;-)。
重复一遍:twisted 中的每个 API,除了callFromThread(以及通过扩展调用 的东西callFromThread,比如blockingCallFromThread)之外,都不是线程安全的。不幸的是,为每个 API 添加警告都会成为代码维护的噩梦,因此一些用户通过调用 API 并注意到一些奇怪的事情,以与您相同的方式发现了此限制。
如果您有一些在需要调用反应器 API 的线程中运行的代码,请使用callFromThreador blockingCallFromThread,它会将调用分派到反应器线程,一切都应该顺利进行。然而,对于定时调用之类的东西,实际上根本不需要使用线程,而且它们会不必要地使您的程序复杂化。
| 归档时间: |
|
| 查看次数: |
4171 次 |
| 最近记录: |