背景
私はかつて、同期的に記述され、スレッドを使用して拡張されたカスタム I/O コードが多数含まれた Python2 システムに取り組んだことがあります。ある時点で、これ以上拡張できなくなり、非同期プログラミングに切り替える必要があることに気付きました。
- ねじれたは人気のある選択肢でしたが、コールバック地獄を避けたいと考えました。
- それは確かに
@inlineCallbacks
デコレータは、他のライブラリと同様に、ジェネレータマジックを使用してコルーチンを効果的に実装しました。これは許容範囲が広かったものの、少し不安定な感じがしました。 - そして私たちはゲヴェントあなたがしなければならなかったのは、次のことだけです:
from gevent import monkey
monkey.patch_all()
そして、まさにそのように、すべての標準 I/O (ソケット、データベース トランザクション、純粋な Python で記述されたすべてのもの) が非同期になり、greenlet を使用して舞台裏で yield および切り替えが行われるようになりました。
完璧ではありませんでした:
- 当時は、Windows ではうまく動作しませんでした (現在でもいくつかの制限があります)。幸いなことに、私たちは Linux 上で実行していました。
- C 拡張機能にモンキーパッチを適用できなかったため、たとえば MySQLdb は使用できませんでした。幸いなことに、PyMySQL など、純粋な Python の代替品は数多くありました。
質問
最近ではPython 3がさらに人気を博しており、非同期個人的には素晴らしいと思いますが、最近、gevent で実装したものとどう違うのかと尋ねられ、十分な答えが思いつきませんでした。
これは主観的に聞こえるかもしれないが、私が実際に探しているのは実際の使用例一方が他方より大幅に優れている場合、または他方ではできないことが可能になります。これまでに私が収集した考慮事項は次のとおりです。
前にも述べたように、gevent は Windows ではかなり制限されています。とはいえ、私が知っているほとんどの製品コードは Linux で動作します。
Windowsで実行する必要がある場合は、asyncioを使用してください。。
GeventはC拡張をモンキーパッチできません。しかし、asyncioはモンキーパッチできません。何でも。
新しい DB テクノロジが登場し、それを使用したいが、それ用の純粋な Python ライブラリがないため、Gevent と統合できないとします。問題は、asyncio と統合できる io* ライブラリがない場合も同様に困ってしまうことです。もちろん、ワーカー スレッドとエグゼキュータはありますが、それは重要ではなく、どちらの場合でも同じように機能します。
個人の好みの問題だと言う人もいますが、同期プログラミングは本質的に非同期プログラミングよりも簡単だと言っても過言ではないと思います (考えてみてください。ソケットは扱えるが、ソケットを適切に選択/ポーリングする方法や、futures/promises で考える方法を理解するのが難しい初心者プログラマーに出会ったことはありませんか? また、その逆の人に出会ったことはありませんか?)。
とにかく、そこは触れないでおこう。この点は頻繁に話題に上がるので、ここで触れておきたい。ここは(Redditでの議論)しかし、私が本当に求めているのは、実用的どちらか一方を使用する理由。
Asyncio は標準ライブラリの一部です。これは非常に大きなことです。つまり、適切に保守され、適切に文書化されており、誰もがそれを知っており、デフォルトで使用しているということです。
しかし、Gevent を使用するのに必要な知識がほとんどないこと (また、Gevent は十分に保守され、ドキュメント化されていること) を考えると、それほど重要ではないようです。したがって、Futures を含む最も複雑なシナリオに対しても StackOverflow に複数の回答がありますが、Futures をまったく使用しない可能性も同様に実現可能であると思われます。
確かに、Guido と Python コミュニティが Asyncio に多大な労力を費やし、言語に新しいキーワードを導入するのには十分な理由があったはずですが、私にはそれを見つけることができないようです。
両者の主な違いは何ですか? また、どのようなシナリオで違いが明らかになりますか?
ベストアンサー1
実際の使用例からの「シンプルな」答え:
- geventの良いところは、パッチつまり、[理論的には]同期ライブラリを使用できるということです。つまり、Django にパッチを適用できます。
- geventの悪いところは、すべてをパッチできるわけではないことです。しなければならないパッチを当てられないDBドライバを使うと、失敗する
- gevent の最も悪い点は、それが「魔法」であることです。「patch_all」で何が起こるかを理解するために必要な労力は膨大で、開発チームに新しい人材を見つけたり雇ったりするのにも同じ労力がかかります。さらに悪いことに、gevent ベースのコードのデバッグは地獄です。コールバックとほぼ同じ地獄、いやそれ以上だと言えるでしょう。
後半のポイントが重要だと思います。ソフトウェアエンジニアリングで最も過小評価されていることは、コードは読む、効果的に書かれていないし、実行もされていない(後者の場合は、Pythonからシステムレベルの言語に切り替えるほうがよい)。Asyncioには非同期プログラミングに欠けている部分がある。事前に定義され、制御されたawait ...
コンテキストスイッチポイント。実際に同期コードを記述し(つまり、突然のスレッドスイッチ、ロック、キューなどについて考えていない)、知る呼び出しは IO をブロックするため、イベント ループで CPU の準備が整った別のものを選択し、後で現在の状態を取得します。
これが asyncio の優れた点です。つまり、メンテナンスが簡単です。欠点は、DB ドライバー、http ツール、ファイル ハンドラーなど、ほぼすべての「世界」も非同期にする必要があることです。また、ライブラリが不足している場合もありますが、これはほぼ間違いありません。