2016-07-14 1 views
1

どうですか?AsyncHTTPClientがトルネードIOLoopをブロックしています

私はこのトラブルを最後まで経験しており、私はトルネードジェネラルライブラリを完全に理解することができないようです。

私は例として、コードのこの部分を持っている:私は思ったよう

@gen.coroutine 
def get(self, build_id=None): 
    status_query = self.get_query_arguments("status") 
    limit_query = self.get_query_arguments("limit") 

    results = [self._dummy() for i in range(15)] 
    yield results 

def _dummy(self): 
    http_client = tornado.httpclient.AsyncHTTPClient() 
    return http_client.fetch("https://www.google.com", headers=self.headers, validate_cert=False) 

は、私の15個の要求は、Googleがほぼ同時にトリガーされなければならないフェッチします。 "results"リストは、先物のリストである必要があります、そして、それらのすべてが完了するのを待つべきリストを生成してください。

これは実際に起こっていますが、リクエストを行うのに約6秒かかりますが、forループの範囲を広げるにつれてますます増えていきます。

準備のために同じ時間をかけてはいけませんか?

何か不足していますか?

ありがとうございました!

+0

リクエストがIOバウンドでない場合、変更はほとんど見られません。 –

+0

もう少し説明していただけますか? :) –

答えて

2

AsyncHTTPClientのデフォルトmax_clientsは10です.15リクエストを開始すると、10リクエストがすぐに開始されますが、残りの5リクエストは完了するまで待たなければなりません。より多くの同時要求を開始するには、max_clientsをより大きな数に増やします。 See Tornado's documentation for details on configuring AsyncHTTPClient.

+0

しかし、これは私の例では、AsyncHTTPClientのインスタンスを1つずつ作成することになります。それぞれが1つのリクエストを作成しています...間違っていますか? –

+0

はい - 内部的には、AsyncHTTPClientオブジェクトは1つの要求キューを共有します。 –

+0

ええ、私はドキュメントでそれを見つけました。それは素晴らしいことです。 Buuuut、私はmax_clientsを50に増やしましたが、それでも同じ問題があります。リクエストを追加するにつれて、依然として時間は徐々に増えています。 (上限を超えないで) –

1

リクエストがIOバウンドでない場合、変更はほとんど見られません。

  • CPU(秒当たり発生する可能性の計算の数)プロセッサで
  • キャッシュアクセス
  • RAMアクセス
  • : - これらをプログラミング Me

は、我々は一次制限されています

  • ディスクアクセス
  • ネットワークアクセス
  • Pythonでは、GILのためにCPUへのアクセスが制限されています。 モダン複数のコア-2,4,8,16に向いているコンピュータの場合、 (これらのプロセッサのそれぞれは、通常、のプロセッサが少し遅くなるため)。 GILの詳細については、David Beazley's GIL talkLarry Hasting's GIL-ectomyを参照してください。

    グローバルインタープリタロックをバイパスするには、Twisted、Tornado、およびasyncioのようないくつかのコールバックスタイルのモジュールが開発されています。これらの作業の仕方は、いくつかの操作を実行することです。通常は、IOが停止するポイントに達すると制御を引き継ぎます。

    たとえば、回転ディスクにデータを書き込んでいるとしたら、おそらくディスクに100kbを書き込むことができますが、その情報がすべて書き込まれるのを待っている間に、すべてのデータが書き込みを終了する前に計算します。

    また、おそらく1秒間に100リクエストをWebサービスに送信することもできますが、リクエストごとに計算を実行するには0.0001秒しかかかりません。あなたは私が私の時間を過ごす場所、このような何かを見に起こってのグラフを見れば:

    #    
        #    
        #    
        #    
        #    
        #    
        #    
        #   # 
    -------------------------- 
    reading processing 
    

    これらのプロセスは、あなたが行うことができどのような要求パケットをオフに送信することにより、処理および読み出し/書き込みをインターリーブであります何か他のことをしてから、ある時点で返されたパケットを読み取ることになります。

     start  end 
    start|  end | 
    --|---|------|---|- 
    t=0 t=1 t=5 t=6 
    

    しかし

    start end start  end 
    --|--------|----|--------|------ 
    t=0  t=5 t=6  t=11 
    

    あなたはこのような何かを得ることができます。むしろこのような何かを探して比べので

    次のように拘束されるものではIO、あなたは、かなり大規模な高速化を見ることができますあなたのプロセスがCPUに縛られていれば、30秒間の処理と1秒間の処理でネットワークを待っているため、そのスピードアップは見られません。

    非同期アプローチを試みる前に、標準のシングルスレッドアプローチを行い、1)十分速ければ、2)ネットワーク/ IO境界では遅い場合を参照してください。

    line profilerのようなものをPython用に簡単に使うことができます。まだ読んでいない場合は、読み込み、処理、書き込みの各機能を分けて、時間をどこに費やしているのかを見てください。あなたが読んでいる関数の中でほとんどの時間を費やしているなら、非同期のアプローチからかなり合理的なスピードアップが見えるはずです。そうでなければ、asyncはあなたを遅らせるでしょう。

    あなたはスーパースピードが重要な何かを持っていない限り、正直なところ、それは、本当に悪いではありません。そして、あなたはcffiか何かを使用してスピードクリティカルセクションを取り出し、Cにダンプする必要があります。はどのセクションがホールドアップであるかを把握していますか?

    +0

    は受け入れる必要があります – desertkun

    関連する問題