2016-08-02 12 views
6

나는 내 파이썬 트위스트 클라인 웹 서비스의 두 가지 기능을 가지고 : os.system("command to upload the written file") 실행, 그것은 "완전한 업로드"다음 "업로드를 시작합니다"라는 메시지가 표시됩니다Twisted Klein에서 비동기 적으로 코드를 실행하는 방법은 무엇입니까?

@inlineCallbacks 
def logging(data): 
    ofile = open("file", "w") 
    ofile.write(data) 
    yield os.system("command to upload the written file") 

@APP.route('/dostuff') 
@inlineCallbacks 
def dostuff(): 
    yield logging(data) 
    print "check!" 
    returnValue("42") 

. 로깅 기능을 비동기로 설정하여 dostuff 처리기가 "check!"를 출력 한 후 logging 처리기에서 처리하도록합니다. (사실 returnValue ("42") 이후에 처리가 이루어지기를 바라지 만, 둘 다 로깅 기능을 비동기식으로 만들고 있습니다.)

yield 문을 사용하면 논 블로킹으로 보이지만 그렇지 않은 것 같습니다. , "수표!" 항상 "업로드 시작"및 "업로드 완료"후에 인쇄됩니다. 비동기 코딩에 익숙하지 않아 잠시 동안 블록 된 적이있는 사람이라면 누구나 내 의견을 나에게 줄 수 있겠습니까? 감사합니다.

답변

3

비동기 코드를 만들려면 Twisted Deferredsdescribed here으로 사용해야합니다. Deferreds는 비동기 코드 실행을위한 API를 제공하며, 콜백을 함수에 첨부 할 수 있으며 원자로 객체가 관리하는 Twisted 이벤트 루프에서 코드를 실행합니다.

귀하의 경우에 Deferreds를 사용할 수있는 두 가지 방법이 있습니다.

1) dostuff 핸들러가 결과에 대해 상관하지 않는 경우이 괜찮 reactor.callLater()

와 백그라운드에서 작업을 실행합니다. reactor.callLater()을 사용할 수 있습니다. 이렇게하면 doStuff에서 값을 반환 한 후 비동기 함수가 실행됩니다.

그래서 이런 식으로 뭔가 :

from klein import run, route, Klein 
from twisted.internet import defer, task, reactor 
import os 

app = Klein() 


def logging(data): 
    ofile = open("file", "w") 
    ofile.write(data) 
    result = os.system("ls") 
    print(result) 


@route('/') 
def dostuff(request): 
    reactor.callLater(0, logging, "some data") 
    print("check!") 
    return b'Hello, world!' 

run("localhost", 8080) 
이 코드 이벤트의 순서는 다음입니다

, 먼저 "안녕하세요!"응답이 반환 및 최종 비동기 호출 suceeds 및 인쇄에 인쇄됩니다 "확인" 실행 결과는 os.system()입니다.

2016-08-11 08:52:33+0200 [-] check! 
2016-08-11 08:52:33+0200 [-] "127.0.0.1" - - [11/Aug/2016:06:52:32 +0000] "GET/HTTP/1.1" 200 13 "-" "curl/7.35.0" 
a.py file 

2) 백그라운드에서 작업을 실행하고 당신이 당신의 '로그'기능의 결과가이 객체에 콜백을 첨부 twisted.internet.task API를 사용하여 신경 경우 task.deferLater()

와 결과를 얻을. 이

@route('/') 
def dostuff(request): 
    def the_end(result): 
     print("executed at the end with result: {}".format(result)) 
    dfd = task.deferLater(reactor, 0, logging, "some data") 
    dfd.addCallback(the_end) 
    print("check!") 
    return b'Hello, world!' 

같은 일을 당신이 당신의 핸들러를 리팩토링하기 위해 필요한이 길을 갈려면 이벤트의이 방법의 순서는 위와 동일합니다,하지만 logging 함수가 끝난 후 the_end 기능은 마지막에 실행됩니다.

2016-08-11 08:59:24+0200 [-] check! 
2016-08-11 08:59:24+0200 [-] "127.0.0.1" - - [11/Aug/2016:06:59:23 +0000] "GET/HTTP/1.1" 200 13 "-" "curl/7.35.0" 
a.py file 
2016-08-11 08:59:24+0200 [-] executed at the end with result: some result 
+0

트위스트 클라인에 대한 지식이 대부분 http://tavendo.com/blog/post/going-asynchronous-from-flask-to-twisted-klein/에서 왔기 때문에 귀하의 응답은 저에게 큰 도움이됩니다. 나는 그것을 시도하지 않았지만 나는 그것이 옳다고 생각할 것이다. 고맙습니다. 정말 고맙습니다. – JLTChiu

+0

업데이트로, 코드는 작동하지만 'E : 512, 4 : Module'twisted.internet.reactor '에 오류를 표시하는 pyCharm과 pylint는'callLater '멤버 (멤버가 없음)가 없습니다.하지만 문제는이 코드입니다. 완전히 잘 보입니다 (의도 한대로 작동 함). 이 문제를 해결할 수있는 방법이 있습니까? – JLTChiu

+1

pycharm 코드 검사에서 버그가있는 것 같습니다. 플랫폼 특정 일 수 있습니까? pycharm이 이와 같은 검사를 수행 할 때, 그리고이 특정 코드와 함께 실패하는 이유를 확인해야합니다. 나 자신 pycharm을 사용하고 나는 그 스타일 경고를 정말로 신뢰하지 않는다, 그들의 많은 것은 틀린 경보 다. flake8은 Python 코드 스타일을 검사하는 더 좋은 도구입니다. IMO –

1

'yield'문으로 비동기식 작업이 수행되지 않습니다. 단지 함수를 포함하는 함수의 실행을 연기하고 나중에 시퀀스를 반복하는 데 사용할 수있는 생성기 객체를 반환합니다.

그래서 dostuff()는 생성자 객체를 반환 할 것입니다. 그 생성자 객체가 언젠가 나중에 반복 될 때까지 아무 일도 일어나지 않을 것입니다. 그러나이 작업을 수행하기위한 코드에는 아무 것도 없습니다. 당신의 dostuff 루틴은 yield와 non-empty return을 포함하고 있기 때문에 구문 오류가 발생할 것으로 예상됩니다. 로깅 루틴은 yield를 포함하고 반환하는 생성기가 사용되지 않기 때문에 아무 것도하지 않습니다.

마지막으로 로깅 루틴은 호출 할 때마다 모드 'w'로 로그 파일을 열 때마다 호출 될 때마다 출력 파일을 자릅니다.

비동기 실행의 경우, 어떤 형태의 다중 처리가 필요합니다. 그러나 나는 이것이 이러한 맥락에서 필요하다고 생각하지 않는다. 로깅 기능은 매우 가볍기 때문에 신속하게 실행해야하며 dostuff의 작업을 방해하지 않아야합니다.

나는 이런 식으로 뭔가를 시도 제안 :

@inlineCallbacks 
def logging(data): 
    try: 
     logging._ofile.write(data + '\n') 
    except AttributeError: 
     logging._ofile = open("file", 'w') 
     logging._ofile.write(data + '\n') 

@APP.route('/dostuff') 
@inlineCallbacks 
def dostuff(): 
    logging("before!") 
    os.system("command to upload the written file") 
    logging("after!") 
    return("42") 

는 여기에서 우리는 _ofile가 로깅의 속성으로 정의되지 않은 경우 처음 로깅가 호출 한 번만 로그 파일을 엽니 다. 후속 호출에서는 logging._ofile이 이미 열려 있고 try 블록의 write 문이 성공적으로 수행됩니다.

dostuff() 루틴은 작업을 수행 중임을 나타 내기 위해 로깅을 호출하고 실제로 작업을 수행 한 다음 로깅을 호출하여 작업이 완료되었음을 나타내며 마지막으로 원하는 값을 반환합니다.

+0

dostuff는 os.system' 콜'에 차단, 코드 샘플에서 비동기, 그래서 진정한 –

+0

dostuff에서 반환하기 전에 인쇄됩니다 '전체 업로드' "업로드 시작"되지 않습니다. Twisted 지식을 사용해 주셔서 감사합니다. –