tornado 非同期リクエストのノンブロッキング

高洛峰
リリース: 2016-10-17 13:58:44
オリジナル
1077 人が閲覧しました

前書き

おそらく一部の学生は混乱しているでしょう: torando は 10K 問題を解決するために非同期でノンブロッキングであると主張していますか? しかし、私は torando が悪いということではなく、それを間違って使用していることに気付きました。 、最近発見したのは、Web サイトのページを開くのが非常に遅い、サーバーの CPU/メモリは正常である、後でページを開くと背面へのアクセス要求が多数あることがわかりました。 -end データベース mongodb データベース ビジネス API の休息サービスがありますが、その竜巻は間違って使用されています。問題を段階的に見てみましょう:


説明

次の例には 2 つの URL があり、1 つは時間です。論理的に言えば、ユーザーは自分のアクセス要求が他の人のアクセス要求に影響を与えたり影響されたりしないことを望んでいると思います。リクエスト


#!/bin/env python

import tornado.httpserver

import tornado.ioloop

import tornado.options

import tornado.web

import tornado.httpclient

輸入時間

からtornado.optionsインポート定義、options

define("port"、default=8000、help="指定されたポートで実行"、type=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、curl、その他のツールを使用して、最初に http://localhost:8000 /sleep にアクセスし、次に http://localhost:8000/justnow にアクセスすると、リクエストが実行されることがわかります。 /jsutnow の場合、すぐに返される可能性があるものは、/sleep リクエストが完了するまでブロックされてから返されます


なぜ私のリクエストが /sleep リクエストによってブロックされるのですか? Web リクエストが通常十分に速い場合は、この問題に気付かないかもしれませんが、実際には時間のかかるプロセスが存在することがよくあります。これは、処理が終了するまでアプリケーションが事実上ロックされていることを意味します


。 @tornado.web.asynchronous デコレータについて考えたことがありますか?ただし、このデコレータを使用するための前提条件は、上記の time.sleep などの時間のかかる実行を行う必要があることです。デコレータを追加するだけでは効果はありません。また、Tornado はデフォルトでクライアントを閉じることに注意してください。関数は接続を終了しますが、@tornado.web.asynchonous デコレータを使用すると、Tornado は接続を自動的に閉じることはなく、self.finish() によって明示的に閉じる必要があります


たとえば、上記の time.sleep には実際には tornado の非同期実装があります:


#!/bin/env python

import tornado.httpserver

import tornado.ioloop

import tornado.options

Import Tornado.Web 、デフォルト = 8000、ヘルプ = "指定されたポートで実行"、タイプ = 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 ("When I Sleep 5s")

Class JustNowHandler (Tor nado.web .RequestHandler):

def get(self):

self.write("今会えることを願っています")

if __name__ == "__main__":

tornado.options.parse_command_line( )app = tornado.web.application(handlers = [

)option.port)

tornado.ioloop.ioloop.instance()は 3.0 以降の新しいデコレータです。以前のメソッドは callbacks を使用するか、私の例を見てください:

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("5秒寝たとき" )

self.finish()

コールバックが使用されていますが、新しいデコレータを使用すると、yield を通じて同じ効果を実現できます。/sleep を開いてから /justnow をクリックすると、justnow リクエストは影響を受けずにすぐに返されます。ただし、非同期デコレータを使用すると、時間がかかります。関数も非同期で実行する必要があります


私が今挙げた例はすべて無意味な例です。これは便利な例です。mongodb データベースのデータを読み取り、それをフロントエンドで 1 行ずつ書き出します


#! /bin/env python

import tornado.httpserver

import tornado.ioloop

import tornado.options

import tornado.web

import tornado.gen

import tornado.httpclient

importトルネード.コンカレント

import tornado.ioloop

import time

# 非同期データベースをサポートするmongodbによって生成されたPythonドライバー

import motor

from tornado.options import define, options

define("port",default=8000, help =" 指定されたポートで実行します", 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)])

# この部分は非同期で非ブロッキングになります。 : : エラーの場合: raise tornado.web.httperror (500, error) )elifメッセージ:self.self.write( '

%s

'%i ['a'])

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

    同僚が、なぜ「できない」と提案しましたこの時間のかかるものを、リクエストをブロックせずに実行するためにツールに非同期的にスローすることはできますか? Rabbitmq と celery をインストールするには:

    #!/bin/env python

    import tornado.httpserver

  • import tornado.ioloop
  • import tornado.options

    import tornado.web

    import tornado.gen

    import tornado.httpclient

    import tcelery、tasks

    import time

    from tornado.options import define、options

    define("port", default=8000, help="指定されたポートで実行", type= int)

    tcelery.setup_nonblocking_Producer()

    class SleepHandler(tornado.web.RequestHandler):

    @tornado.web.asynchronous

    @tornado.gen.coroutine

    def get(self):

    # tornado Gen.タスクのパラメータは: 実行される関数、パラメータ

    yield tornado.gen.task (tasks.sleep.apply_async, args = [5])

    Self.write ("When I Sleep 5s")

    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 = httpserver。 HTTPServer(app)

    http_server.listen(options.port)

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

    task は、私たちが話している time.sleep を含む celery のタスク定義ファイルです。

    輸入時間

    セロリの輸入から

    celery = Celery("タスク", 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ワーカーを開始します(そうでない場合、タスクはどのように実行されますか?は間違いなく必要です。消費者がそれを奪います):


    celery -A タスクワーカー --loglevel=info

    しかし、ここでの問題も深刻である可能性があります。非同期ノンブロッキングはセロリ、またはこの長さに依存します。キュー、タスクが多数ある場合、待機する必要がありますが、これは非常に非効率です。同期ブロック機能を非同期に変更する方法はありますか?


    # !/bin/env python

    import tornado.httpserver

    import tornado.ioloop

    import tornado.options

    import tornado.web

    import tornado.httpclient

    import tornado.gen

    from現在のインポート run_on_executor

    # この同時実行ライブラリ python3 では、 sudo pip install futures をインストールする必要があります

    from concurrent.futures import ThreadPoolExecutor

    import time

    from tornado.options import define, options

    define("port",default=8000) , help="指定されたポートで実行します", type=int)

    class SleepHandler(tornado.web.RequestHandler):

    executor = ThreadPoolExecutor(2)

    #executor はグローバルではなくローカル変数です

    @tornado。 web.asynchronous

    @tornado.gen.coroutine

    def get(self):

    # 実行する非同期実行が値を返し、呼び出され続ける場合は、これを行うことができます (デモンストレーションのみ)。それ以外の場合は、単にyield 直接

    res = yield self.sleep() I Self.write ("WHEN I SLEEP % 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("i wish just now see you")

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

    関連ラベル:
    ソース:php.cn
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート