2013-07-20 2 views
4

라즈베리 파이의 GPIO를 사용하여 파이썬에서 운동을 감지하고 사이렌을 작동시키는 홈 보안 프로그램을 만들었습니다. 사용자는 라스베리 파이에 연결된 NFC 태그에 NFC 태그를 사용하여 시스템을 활성화/비활성화합니다.다른 스레드에서 비틀어 진 프로토콜 메서드 호출

이렇게하려면 항상 비 차단 방식으로 nfc 태그를 확인해야하며 동시에 센서가 비 차단 상태인지 지속적으로 확인해야합니다. 더 많은 평행선이 필요하지만이 두 점만으로도 충분하다고 생각합니다.

지금 당장은 내가 시작/멈추는 쓰레드를 사용합니다. - Stopping a thread after a certain amount of time - 이것이 최적의 방법인지는 확실하지 않지만 시스템은 정상적으로 작동합니다.

이제는 웹 소켓을 통해 알림 기능을 제공하기 위해 기능을 확장하려고합니다. 나는의 send 메소드를 호출 할 수있는 방법 그래서

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() 

: 나는 여기

내가 그것을하려고하는 방법에 대한 예제 코드입니다 ..이 트위스트와 함께 할 수 있지만, 내가 혼란 스러워요 발견 thread1과 같은 스레드의 서버 프로토콜?

답변

5

종종 스레드와 Twisted에 대한 질문에 대한 대답은 "스레드를 사용하지 않습니다."입니다.

스레드를 여기에서 시작하는 이유는 GPIO 센서를 반복적으로 확인할 수있는 것처럼 보입니다. 센서 블록을 점검합니까? GPIO라면 로컬에서 사용할 수있는 하드웨어이므로 그 결과를 즉시 사용할 수 있기 때문에 추측하고 있습니다. 하지만 나는 두 가지 대답을 줄 것이다.

여기서 스레드를 사용하는 주된 이유는 일을 반복적으로 수행하는 것입니다.. Twisted에서 반복적으로 작업하고 싶다면 스레드를 사용하지 않아도됩니다 :). Twisted는 반복 작업을위한 훌륭한 API 인 LoopingCall을 포함합니다. 귀하의 예는 다음과 같을 것이다 (GPIO를 호출 차단하지 않습니다 가정, 다시) LoopingCall를 사용하여 다시 작성 :

물론
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() 

, 당신은 여전히 ​​스레드를 사용할 필요 한 경우가 다음 경우 GPIO 검사기 (또는 되풀이 작업이 무엇이든간에)는 스레드에서 실행해야합니다. 라이브러리에서 잠재적으로 블로킹 작업이므로 Twisted를 더 잘 사용하도록 수정할 수 없으며 기본 루프를 차단하지 않으려 고합니다. . 당신이 부르고 LoopingCall, 다음은 Deferred 때까지 다시 함수를 호출하지 않습니다 기능에서 Deferred을 반환하는 경우 :이 경우

, 당신은 여전히 ​​ LoopingCall를 사용하고, 그 기능의 또 다른 하나의 장점을 먹고 싶어 화재. 즉, 스레드에 작업을 셔틀 할 수 있으며 스레드가 완료 될 때 주 스레드에서 자동으로 루프를 재개 할 수 있습니다.

내가 의미하는 바를 구체적으로 알려면 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) 

위의 예에 대한 내용은 모두 동일합니다.

+2

이것은 매우 설명적인 답변입니다. 감사합니다. 나는 이것이 내 질문에 답할 수 있다고 생각하며 나는이 프로젝트로 돌아갈 때 며칠 만에 그것을 점검 할 것이다. 며칠 * 응답 * 버튼을 지연 시키면 문제가되지 않기를 바랍니다. – kapcom01

2

예제에는 몇 가지 요인이 있습니다. 짧은 대답 : 연구 this documentation on threads in Twisted. 당신이 프로토콜 클래스 (스레딩 및 프로토콜 구현이 분리되어있다)를 사용하는 트위스트의 원자로를 사용하는이없는 할 동안

  • , 그렇게 모든 I 아래 당신에 적용되는 고려의 reactor.run라고했다.
  • Twisted가 자동으로 스레드를 생성합니다. 프레임 워크 외부로 나가면 문제가 발생할 수 있습니다. 원자로와의 IPC 메시징을위한 "공용"API는 없습니다 (필자는 생각합니다). 따라서 Twisted를 사용하면 모든 것을 진행해야합니다.
  • 기본적으로 Twisted는 콜백을 호출하기 위해 스레드를 전환하지 않습니다. 주 원자로 스레드에서 작업자 스레드로 위임하려면 (즉, I/O 차단 수행) 사용자가 직접 스레드를 작성할 필요가 없으며 reactor.callInThread을 사용하면 작업자 스레드에서 실행됩니다. 이렇게하지 않으면 모든 것이 주 리액터 스레드에서 실행됩니다. 예를 들어 모든 I/O 작업이 원자로 스레드를 차단하고 I/O가 완료 될 때까지 이벤트를 수신 할 수 없습니다.
  • 작업자 스레드에서 실행되는 코드는 스레드로부터 안전하지 않은 모든 작업을 수행하려면 reactor.callFromThread을 사용해야합니다. 메인 리액터 스레드에서 실행되는 콜백을 제공하십시오. 여기 미안보다 안전 해. 날 믿어.
  • 위의 모든 내용은 Deferred 처리에도 적용됩니다. 따라서 콜백을 설정할 때 mycallback 대신 partial(reactor.callFromThread, mycallback) 또는 partial(reactor.callInThread, mycallback)을 사용하는 것을 두려워하지 마십시오. 나는 어려운 길을 배웠다. 그것 없이는 지연 콜백에서 수행 할 수있는 차단 I/O가 스레드 안전 문제로 인해 오류가 발생하거나 주 스레드를 차단하고있는 것으로 나타났습니다.

방금 ​​Twisted에서 시작한다면 '신뢰 가을'입니다. Queue 개체 등을 통해 자신의 스레드를 관리하고 메시지를 전달하는 방법을 배우십시오. Deferred과 원자로가 작동하는 이유 (이유 때문에 "꼬임"이라고 불리는 방식)을 파악하면 완벽하게 자연스러워 보일 것입니다. Twisted는 함수 프로그래밍 스타일에서 문제를 분리하고 분리하도록 강요하지만, 일단 끝나면 매우 깨끗하고 잘 작동하는 것으로 나타났습니다.

하나의 팁 : 내가 지속적으로 callInThreadcallFromThread를 호출하고 코드에 걸쳐 콜백을 처리 예외 Deferred을 설정 할 필요가 없었어요 그래서 내 모든 콜백 함수에 사용하는 몇 가지 장식을 썼다; 내 데코레이터는 저를 위해 그 행동을 가능하게합니다. 버그를 잊어 버리는 것을 막을 가능성이 있으며 트위스티드 개발이 나에게 더 유쾌하게 만들어졌습니다.

+0

감사합니다. 제안한 설명서를 읽었습니다. 내 Threads을 대체하기 위해 완전히 뒤틀린 것을 고려해야합니다. 나는 며칠 만에 프로젝트에 다시 올 것이다. – kapcom01

관련 문제