tornadoユーザーガイド(二)---------tornado協程実現使用と原理(一)


Tornadoは、非同期呼び出しを実現するためにコプロセッサを使用することを推奨します.
コパスはpythonのyieldキーワードを使用して、callback関数を大量に記述することなく、実行を継続または一時停止します.(linuxのepollベースの非同期呼び出しでは、非同期実行結果に大量のcallback関数を明示的にインストールする必要がある).
コラボレーションの使用は、非同期コードの作成と同様に簡単であり、スレッドのオーバーヘッドを省くことができます.
コラボレーションにより、コンカレント・プログラムの作成が容易になり、コンテキスト・スイッチングのオーバーヘッドが発生しません.
例:
from tornado import gen

@gen.coroutine
def fetch_coroutine(url):
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch(url)
    #  python3.3      ,                  。                    。
    return response.body

@gen.coroutineはtornadoが実装したジェネレータで、fetch_coroutine関数は1つのコヒーレンスにパッケージされ,このコヒーレンスをスレッドと等価な実行体とすることができる.この実行体験はtornadoの全体的なioloopによって呼び出され、ブロックが必要なときに他のコモンシップ実行に切り替えられ、ブロック呼び出しが完了するとioloopはこの準備されたコモンシップを実行し続ける.このようにして、1つのスレッドで複数のコモンシップを実行することができ、あるコモンシップブロックのために他の準備されたコモンシップをブロックすることはない.
実現原理:
パッケージされた関数はFutureを返します.このコンセンサスが本当に実行されると、Futureの実行結果が設定されます.このコヒーレンス実行が完了し、結果が得られるのをyieldで待つことができる.
コンセンサス実行時yield http_client.fetchの場合、この操作はネットワークI/O操作であるため、ブロック操作に属する.したがって、このコヒーレンスは実行を一時停止し、tornadoの全体的なioloopは他のコヒーレンスを実行することができる.
コパスでは、yield文がブロックされている関数は、非同期実行体を表し、非同期操作の実行が完了したときにFutureの結果を設定するFutureを返す必要があります.tornadoは、Futureの実行が完了したときに、Futureの実行結果をジェネレータのsendメソッドでyield文に値を返し、ブロックされているコパスを起動して実行を続行します.
実装上、http_client.fetch操作は、tornado ioloopにfdを追加することによって真の非同期操作を実現し、fetchが本当に成功した場合、すなわちepollが戻ると、Futureの結果が設定され、このコラボレーションが起動して実行されます.
以上、tornadoのコラボレーション機能を利用するには、@gen.coroutineで関数をパッケージし、ブロックが必要な場所でyield文でブロックする必要があります.ブロックされたコードはFutureを返し、何らかの非同期でFutureの実行結果を設定する必要があります.
tornadoプロセスの使用例:
1.完了するまで、コプロセッサでブロック操作を実行しないことができます.
2つのコヒーレンスと1つの合計コヒーレンスを作成し,コヒーレンスにはブロック操作がないため,実際には2つのコヒーレンスが順次実行される.
from tornado import gen
from tornado.ioloop import IOLoop

@gen.coroutine
def cor(n,str):
    for i in range(n):
       print(str,i)
    return str

@gen.coroutine
def main():
    cor(3,"first")
    cor(4,"second")

IOLoop.instance().run_sync(main)
 
 
2.        :
               ,  sleep tornado     ,         ,  yield      future.
  , main       yield  ,      2         ioloop.         。
  ,    2       ,sleep             。
from tornado import gen
from tornado.ioloop import IOLoop

@gen.coroutine
def cor(n,str):
    for i in range(n):
       print(str,n)
       yield gen.sleep(1)
    return str

@gen.coroutine
def main():
    cor(3,"first")
    cor(3,"second")
    yield gen.sleep(3)

IOLoop.instance().run_sync(main)
3.   2 main          ,  main              ,     2   。
@gen.coroutine
def main():
    yield cor(3,"first")
    yield cor(3,"second")

IOLoop.instance().run_sync(main)