kap*_*m01 4 python multithreading twisted websocket
我用Python创建了一个Home Security程序,它使用Raspberry Pi的GPIO来感知运动并启动警报器.用户使用NFC标签激活/停用系统,也可以连接到覆盆子pi的nfc reder.
为此,我需要不间断地检查nfc标签,同时不断检查传感器的运动是否也无阻塞.我需要一些更平行的东西,但我认为这两个足以说明问题.
现在我使用我开始/ 停止的线程 - 在一段时间后停止线程 - 我不确定这是否是最佳方式,但截至目前系统工作正常.
现在我想扩展其功能,通过websockets提供通知.我发现这可以用Twisted完成,但我很困惑..
以下是我尝试执行此操作的示例代码:
from twisted.internet import reactor
from autobahn.websocket import WebSocketServerFactory, \
WebSocketServerProtocol, \
listenWS
def thread1(stop_event):
while(not stop_event.is_set()):
stop_event.wait(4)
print "checking sensor"
# sensor_state = GPIO.input(11)
if sensor_state == 1:
# how can I call send_m("sensor detected movement") #<---
t1_stop_event.set()
t1_stop_event = Event()
t1 = Thread(target=thread1, args=(t1_stop_event,))
class EchoServerProtocol(WebSocketServerProtocol):
def onMessage(self, msg, binary):
print "received: "+msg
print "stopping thread1"
t1_stop_event.set()
def send_m(self, msg):
self.sendMessage(msg)
if __name__ == '__main__':
t1.start()
factory = WebSocketServerFactory("ws://localhost:9000")
factory.protocol = EchoServerProtocol
listenWS(factory)
reactor.run()
Run Code Online (Sandbox Code Playgroud)
那么如何从thread1这样的线程调用服务器协议的send方法呢?
通常情况下,关于线程和Twisted的问题的答案是" 不要使用线程 ".
您在此处启动线程的原因似乎是您可以重复检查GPIO传感器.检查传感器块?我猜不是,因为如果它是GPIO,它是本地可用的硬件,其结果将立即可用.但我会两种方式给你答案.
你在这里使用线程的主要事情是重复做一些事情.如果你想在Twisted中重复做一些事情,就没有理由使用线程 :).Twisted包含一个用于重复任务的优秀API : LoopingCall. 您重新编写使用的示例LoopingCall(再次假设GPIO调用未阻止)将如下所示:
from somewhere import GPIO
from twisted.internet import reactor, task
from autobahn.websocket import WebSocketServerFactory, \
WebSocketServerProtocol, \
listenWS
class EchoServerProtocol(WebSocketServerProtocol):
def check_movement(self):
print "checking sensor"
sensor_state = GPIO.input(11)
if sensor_state == 1:
self.send_m("sensor detected movement")
def connectionMade(self):
WebSocketServerProtocol.connectionMade(self)
self.movement_checker = task.LoopingCall(self.check_movement)
self.movement_checker.start(4)
def onMessage(self, msg, binary):
self.movement_checker.stop()
def send_m(self, msg):
self.sendMessage(msg)
if __name__ == '__main__':
factory = WebSocketServerFactory("ws://localhost:9000")
factory.protocol = EchoServerProtocol
listenWS(factory)
reactor.run()
Run Code Online (Sandbox Code Playgroud)
当然,有一种情况你仍然需要使用线程:如果GPIO检查程序(或任何你的重复任务)需要在一个线程中运行,因为它是一个无法修改为库的库中的潜在阻塞操作更好地利用Twisted,你不想阻止主循环.
在这种情况下,你仍想使用LoopingCall,并充分利用其功能又一个的:如果你返回Deferred从该函数LoopingCall被调用,那么它将不会再调用这个函数,直到Deferred火灾.这意味着您可以将任务传递给线程,而不必担心主循环堆积该线程的查询:您可以在线程完成时自动恢复主线程上的循环.
为了让你明白我的意思更具体的想法,这里的check_movement修改与在一个线程中运行长时间运行的阻塞呼叫工作,而不是可以在主循环运行的快速轮询呼叫,功能:
def check_movement(self):
from twisted.internet.threads import deferToThread
def get_input():
# this is run in a thread
return GPIO.input(11)
def check_input(sensor_state):
# this is back on the main thread, and can safely call send_m
if sensor_state == 1:
self.send_m("sensor movement detected")
return deferToThread(get_input).addCallback(check_input)
Run Code Online (Sandbox Code Playgroud)
关于上述示例的所有其他内容保持完全相同.
| 归档时间: |
|
| 查看次数: |
2803 次 |
| 最近记录: |