>백엔드 개발 >파이썬 튜토리얼 >토네이도 비동기 요청 비차단

토네이도 비동기 요청 비차단

高洛峰
高洛峰원래의
2016-10-17 13:58:441083검색

서문

일부 학생들은 혼란스러울 수 있습니다. 토네이도는 10K 문제를 해결하기 위해 비동기식 및 비차단식이라고 주장하지 않습니까? 하지만 토란도가 나쁘다는 것이 아니라 여러분이 예를 들어, 최근에 발견한 바에 따르면, 특정 웹사이트에서 페이지를 여는 속도가 매우 느리고, 서버 CPU/메모리도 정상이었습니다. 나중에 페이지를 열 때, 백엔드 데이터베이스 접근 요청이 많았고, mongodb 데이터베이스 비즈니스 API의 나머지 서비스도 있었는데, 잘못 사용했다면 단계별로 문제를 연구해보세요:


설명

다음 예에는 URL이 두 개 있는데, 하나는 시간이 많이 걸리는 요청이고, 다른 하나는 즉시 반환될 수 있거나 필요한 요청인 것 같습니다. 기술에 익숙하지 않은 사용자라도 논리적으로 말하면 자신의 액세스 요청이 다른 사람의 요청에 영향을 미치거나 영향을 받지 않기를 바랍니다


#!/bin /env python

tornado.httpserver 가져오기

tornado.ioloop 가져오기

tornado.options 가져오기

tornado.web 가져오기

가져오기 tornado.httpclient

가져오기 시간

from tornado.options import 정의, 옵션

define("port ", default=8000, help="지정된 포트에서 실행" , 유형=int)

class SleepHandler(tornado.web.RequestHandler):

def get(self):

time.sleep(5)

self.write("내가 5초 잘 때")

class JustNowHandler(tornado.web.RequestHandler):

def get(self):

self.write( "지금 바로 만나길 바랍니다")

if __name__ == "__main__":

tornado.options.parse_command_line( )

app = tornado.web.Application( handlers=[

) (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])

http_server = tornado.httpserver.HTTPServer(app)

http_server.listen(options.port)

tornado.ioloop.IOLoop.instance().start()

페이지 요청을 사용하거나 httpie, 컬 및 기타 도구를 사용하는 경우 먼저 http://localhost:8000/sleep에 액세스한 다음 http://localhost:8000/justnow에 액세스하면 즉시 반환될 수 있었던 /jsutnow에 대한 요청이 /sleep 요청이 있을 때까지 차단됩니다.


왜 내 요청이 /sleep 요청에 의해 차단되나요? 웹 요청이 일반적으로 충분히 빠르면 이 문제를 인식하지 못할 수도 있지만 실제로는 시간이 많이 걸리는 프로세스가 있기 때문에 처리가 끝날 때까지 애플리케이션이 효과적으로 잠깁니다.


이때 @tornado.web.asynchronous 데코레이터를 기억하시나요? 하지만 이 데코레이터를 사용하기 위한 전제 조건은 위의 time.sleep과 같이 시간이 많이 걸리는 실행을 위해 비동기 실행을 수행해야 한다는 것입니다. 데코레이터를 추가하는 것만으로는 효과가 없으며 Tornado는 기본적으로 클라이언트를 닫는다는 점에 유의해야 합니다. 함수는 연결 종료를 반환하지만 @tornado.web.asynchonous 데코레이터를 사용하면 Tornado는 연결을 자동으로 닫지 않으며 self.finish()


대부분의 함수는 차단됩니다. 예를 들어 위의 time.sleep은 실제로 토네이도에서 비동기 구현을 갖습니다.


#!/bin/ env python

tornado.httpserver 가져오기

tornado.ioloop 가져오기

tornado.options 가져오기

tornado.web 가져오기

tornado 가져오기 .gen

tornado.httpclient 가져오기

tornado.concurrent 가져오기

tornado.ioloop 가져오기

tornado.options에서 시간 가져오기

가져오기 정의, 옵션

define("port", default=8000, help="지정된 포트에서 실행", type=int)

class SleepHandler(tornado.web.RequestHandler):

@tornado.web.asynchronous

@tornado.gen.coroutine

def get(self):

yield tornado.gen.Task(tornado .ioloop.IOloop.instance ().add_timeout, time.time() + 5)

self.write("내가 5초 동안 잠을 잘 때")

class JustNowHandler(tornado.web.RequestHandler ):

def get(self):

self.write("지금 바로 만나길 바랍니다")

if __name__ == "__main__":

tornado.options .parse_command_line()

app = tornado.web.Application(handlers=[

(r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])

http_server = tornado.httpserver.HTTPServer(app)

http_server.listen(options.port)

tornado.ioloop.IOLoop.instance(). start()

여기에 새로운 tornado.gen.coroutine 데코레이터가 있습니다. Coroutine은 3.0 이후의 새로운 데코레이터입니다. 이전 방법은 콜백을 사용하거나 제 예를 살펴보는 것이었습니다:


class SleepHandler(tornado.web.RequestHandler):

@tornado.web.asynchronous

def get(self):

tornado. ioloop.IOloop.instance().add_timeout(time.time() + 5, callback=self.on_response)

def on_response(self):

self.write("잠잘 때 5s")

self.finish()

콜백이 사용되지만 새로운 데코레이터를 사용하면 항복을 통해 동일한 효과를 얻을 수 있습니다. /sleep을 열고 /justnow를 클릭하면 justnow 요청은 영향을 받지 않고 즉시 반환됩니다. 그러나 비동기 데코레이터가 사용됩니다. -소비 함수도 비동기식으로 실행해야 합니다.


방금 언급한 예는 의미가 없습니다. 다음은 유용한 예입니다. mongodb 데이터베이스 데이터를 읽은 다음 프런트 엔드에서 이를 작성합니다. 한 줄씩


#!/bin/env python

import tornado.httpserver

import tornado.ioloop

tornado.options 가져오기

tornado.web 가져오기

tornado.gen 가져오기

tornado.httpclient 가져오기

tornado.concurrent 가져오기

import tornado.ioloop

가져오기 시간

# tornado에서 비동기 데이터베이스

가져오기 모터

를 지원하는 mongodb에서 생성된 Python 드라이버 가져오기 옵션을 정의합니다. , options

define("port", default=8000, help="run on the 주어진 포트", type=int)

# db는 실제로 테스트 데이터베이스의 커서입니다

db = motor.MotorClient().open_sync().test

class SleepHandler(BaseHandler):

@tornado.web.asynchronous

@tornado . gen.coroutine

def get(self):

# 이 줄의 실행을 차단하는 데 여전히 시간이 걸립니다. 내 tt 컬렉션에 일부 데이터가 있고 색인이 없습니다.

커서 = db.tt.find().sort([('a', -1)])

               # 이 부분은 다른 페이지 요청에 영향을 주지 않고 비동기식 및 비차단 방식으로 실행됩니다.

                              yield cursor.fetch_next):

message =cursor.next_object()

self.write('

  • %s
  • ' % message['a'])

    self.write('')

    self.finish()

    def _on_response(self, message, error):

    if error:

    tornado.web.httperror (500, 오류)

    Elif 메시지:

    FOR I in Message:

    Self.write ('

    > %s

  • ' % i['a'])
  •                                                                                > def get(self):

    자기 .write("지금 바로 만나길 바랍니다")

    if __name__ == "__main__":

    tornado.options.parse_command_line()

    app = tornado.web .Application(handlers=[

    ) (r"/sleep", SleepHandler ), (r"/justnow", JustNowHandler)])

    http_server = tornado.httpserver.HTTPServer(app)

    http_server.listen(options.port)

    tornado .ioloop.IOloop.instance().start()

    동료가 왜 이렇게 시간이 많이 걸리는 일을 할 수 없는지 물었습니다. 내 요청을 차단하지 않고 비동기적으로 실행 도구에 던져졌나요? 글쎄요, 저도 생각해 봤습니다. 예: celery, 그냥 github에 tornado-celery

    실행하려면 다음 프로그램을 사용하려면 먼저 Rabbitmq와 celery를 설치해야 합니다.

    #!/bin/env python

    import tornado.httpserver

    tornado.ioloop 가져오기

    tornado.options 가져오기


    tornado.web 가져오기

    tornado.gen 가져오기

    tornado.httpclient 가져오기

    import tcelery, 작업

    가져오기 시간

    from tornado.options import 정의, 옵션

    define("port", default=8000, help="지정된 포트에서 실행) ", 유형=int)

    tcelery.setup_nonblocking_producer()

    class SleepHandler(tornado.web.RequestHandler):

    @tornado.web.asynchronous

    @tornado.gen.coroutine

    def get(self):

    # tornado.gen.Task의 매개변수는 다음과 같습니다: 실행할 함수, 매개변수

    Yield tornado.gen.Task(tasks.sleep.apply_async, args=[5])

    self.write("5초 동안 잠을 자면")

    self.finish()

    class JustNowHandler(tornado.web.RequestHandler):

    def get(self):

    self.write("지금 막 만나길 바랍니다")

    if __name__ == "__main__":

    tornado.options.parse_command_line()

    app = tornado.web.Application(handlers=[

    (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])

    http_server = tornado.httpserver.HTTPServer(app)

    http_server.listen(options.port)

    tornado.ioloop.IOLoop.instance().start()

    작업은 셀러리의 작업입니다. 정의된 파일에는 우리가 말하는 time.sleep 함수가 포함되어 있습니다.

    가져오기 시간

    from celery import Celery

    celery = Celery("tasks",broker="amqp://guest:guest@localhost:5672")

    celery.conf.CELERY_RESULT_BACKEND = "amqp"

    @celery .task

    def sleep(초):

    time.sleep(float(초))

    초 반환

    if __name__ == "__main__" :

    celery.start()

    그런 다음 셀러리 작업자를 시작합니다(그렇지 않으면 작업을 어떻게 실행합니까? 소비자가 가져가야 합니다):


    celery -A 작업 작업자 --loglevel=info

    그러나 여기서 문제는 심각할 수도 있습니다. 비동기 비차단은 셀러리 또는 대기열 길이(있는 경우)에 따라 달라집니다. 작업이 많으면 기다려야 하는데 이는 매우 비효율적입니다. 동기식 차단 기능을 비동기식으로 변경하는 방법이 있나요(또는 토네이도의 데코레이터에서 이해하고 인식할 수 있나요?) >

    #!/bin/env python


    tornado.httpserver 가져오기

    tornado.ioloop 가져오기

    tornado.options 가져오기

    tornado 가져오기. web

    import tornado.httpclient

    import tornado.gen

    from tornado.concurrent import run_on_executor

    # 이 동시성 라이브러리는 python3과 함께 제공됩니다. sudo pip를 설치해야 합니다. futures 설치

    from Concurrent.futures import ThreadPoolExecutor

    가져오기 시간

    from tornado.options import 정의, 옵션

    define ("port", 기본값= 8000, help="지정된 포트에서 실행", type=int)

    class SleepHandler(tornado.web.RequestHandler):

    executor = ThreadPoolExecutor(2 )

    #executor는 전역 변수가 아닌 지역 변수입니다.

    @tornado.web.asynchronous

    @tornado.gen.coroutine

    def get(self ):

    # 수행하는 비동기 실행이 값을 반환하고 계속 호출되는 경우 이 작업을 수행할 수 있습니다(시연용으로만). 그렇지 않으면 직접 항복

    res = 항복 self. sleep()

    self.write("내가 잠잘 때 %s s" % res)

    self.finish()

    @run_on_executor

    def sleep (self):

    time.sleep(5 )

    return 5

    class JustNowHandler(tornado.web.RequestHandler):

    def get(self ):

    self.write("지금 만나길 바랍니다")

    if __name__ == "__main__":

    tornado.options.parse_command_line()

    app = tornado.web.Application(handlers=[

                                                                      사용   다음과 함께 사용                              통해  부터 통해 통해 오프 ' s  ‐   ‐ ‐ ​ ​ ​ ​ ​ .listen(options.port )

    tornado.ioloop.IOloop.instance().start()

    성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.