9

Gevent / Eventletモンキーパッチを実行した後-DBドライバー(例:redis-pypymongo)が標準ライブラリ(例socket)を介してIOを使用する場合は常に非同期になると想定できますか?

したがって、イベントレットのモンキーパッチを使用するだけで、たとえば次のようになります。イベントレットアプリケーションでredis-pyノンブロッキング?

私が知っていることから、接続の使用法に注意すれば十分なはずです(たとえば、グリーンレットごとに異なる接続を使用するなど)。しかし、私は確信したい。

他に何が必要か、またはGevent / EventletでDBドライバーを正しく使用する方法を知っている場合は、それも入力してください。

4

2 に答える 2

18

次のすべてが当てはまる場合は、魔法のようにパッチが適用されると想定できます。

  • I / Oは、標準のPythonまたは/ monkeypatchessocketの他のものの上に構築されていることを確認してください。ファイル、ネイティブ(C)ソケットオブジェクトなどはありません。eventletgevent
  • aggressive=Trueに渡すpatch_all(またはpatch_select)、またはライブラリが使用しない、selectまたは同様のものがないことを確認します。
  • ドライバは(暗黙の)内部スレッドを使用しません。(ドライバー内部でスレッドを使用する場合、機能するpatch_thread 可能性がありますが、機能しない可能性があります。)

よくわからない場合は、テストするのは非常に簡単です。おそらく、コードを読んで解決しようとするよりも簡単です。次のようなことを行うグリーンレットを1つ用意します。

while True:
    print("running")
    gevent.sleep(0.1)

次に、データベースに対して低速のクエリを実行する別のクエリを用意します。モンキーパッチが適用されている場合、ループするグリーンレットは1秒間に10回「実行中」の印刷を続けます。そうでない場合、プログラムがクエリでブロックされている間、ループするグリーンレットは実行されません。

それで、あなたのドライバーがブロックした場合、あなたはどうしますか?

最も簡単な解決策は、DBクエリに真の同時スレッドプールを使用することです。アイデアは、スレッドプールジョブとして各クエリ(またはバッチ)を起動geventし、そのジョブの完了時にグリーンレットブロックすることです。(多くの同時クエリを必要としない非常に単純なケースでは、threading.Thread代わりにクエリごとにを生成することができますが、通常はそれを回避することはできません。)

ドライバーが重要なCPU作業を行う場合(たとえば、インプロセスキャッシュを実行するもの、またはsqliteなどのインプロセスDBMS全体を使用している場合)、このスレッドプールを実際にプロセスの上に実装する必要があります。 GILはあなたgreenletsの実行を妨げる可能性があります。それ以外の場合(特にWindowsが気になる場合)は、おそらくOSスレッドを使用することをお勧めします。(ただし、これはできないことを意味しますpatch_threads()。それが必要な場合は、プロセスを使用してください。)

を使用していてeventlet、スレッドを使用したい場合は、それと呼ばれる組み込みの単純なソリューションtpoolで十分な場合があります。を使用している場合gevent、またはプロセスを使用する必要がある場合、これは機能しません。残念ながら、実際のスレッドオブジェクトで(イベントループ全体をブロックせずに)グリーンレットをブロックすることは、との間eventletで少し異なりgevent、十分に文書化されていませんが、tpoolソースからアイデアが得られるはずです。その部分を超えて、残りはaまたはでタスクを実行するために使用しているだけです(2.xまたは3.1でこれが必要な場合はpypiconcurrent.futuresを参照してください) 。(または、必要に応じて、すぐに使用することも、使用する代わりに使用することもできます。)futuresThreadPoolExecutorProcessPoolExecutorthreadingmultiprocessingfutures


WindowsでOSスレッドを使用する理由を説明できますか?

簡単な要約は次のとおりです。スレッドに固執する場合は、ほとんどクロスプラットフォームのコードを記述できますが、プロセスに移動する場合は、2つの異なるプラットフォームのコードを効果的に記述しています。

まず、モジュールのプログラミングガイドラインをお読みくださいmultiprocessing(「すべてのプラットフォーム」セクションと「Windows」セクションの両方)。幸いなことに、DBラッパーはこれのほとんどに遭遇するべきではありません。を介してプロセスを処理する必要があるだけですProcessPoolExecutor。また、カーソル操作レベルでもクエリレベルでも、すべての引数と戻り値は、ピクルス化できる単純な型になります。それでも、それはあなたが注意しなければならないことであり、そうでなければ問題にはなりません。

一方、Windowsのプロセス内同期オブジェクトのオーバーヘッドは非常に低くなりますが、プロセス間同期オブジェクトのオーバーヘッドは非常に高くなります。(スレッドの作成も非常に速く、プロセスの作成も非常に遅いですが、プールを使用している場合は重要ではありません。)では、どのように対処しますか?クロスプロセス同期オブジェクトを待機してグリーンレットに信号を送るOSスレッドを作成するのはとても楽しかったですが、楽しみの定義は異なる場合があります。

最後に、 Unix用tpoolに簡単に適応させることができますがppool、Windowsではより多くの作業が必要になります(そして、その作業を行うにはWindowsを理解する必要があります)。

于 2013-01-24T01:55:45.907 に答える
2

abarnertの答えは正しく、非常に包括的です。イベントレットには「積極的な」パッチはなく、おそらくgevent機能であると付け加えたいと思います。また、ライブラリがそれを使用selectする場合、それは問題ではありません。なぜなら、eventletはそれをモンキーパッチすることもできるからです。

実際、ほとんどの場合、eventlet.monkey_patch()必要なのはそれだけです。もちろん、ソケットを作成する前に行う必要があります。

それでも問題が解決しない場合は、問題を開くか、イベントレットのメーリングリストまたはG+コミュニティにご連絡ください。関連するすべてのリンクはhttp://eventlet.net/で見つけることができます

于 2013-01-24T09:27:38.890 に答える