Manjusaka

Manjusaka

async/await の道へ進む

async/await への道#

彭総の記事「この Python はくそ」(https://zhuanlan.zhihu.com/p/45936509)を見て、感慨深いものがあり、私も水を差しましょう。

まず、私たちの会社は新しいものに挑戦することに勇気を持っていると言えるでしょう。具体的な表れは、関連する基本サービスの追加を迅速に追いかけ、新しいものに挑戦することです。ええ、昨年 6 月から現在まで、私たちの会社ではかなり長い間、async/await を本番環境で実施し、新しいフレームワークである Sanic を導入しましたが、残念ながら、私たちは今、一時的に async/await に別れを告げなければなりません。

なぜ async/await を選んだのか?#

私たちのチームの具体的なシナリオに関連しています。私たちのチームでは、さまざまな URL に基づいて異なるサブサービスからデータをリクエストし、それを組み合わせて次の統一処理を行います。このような場合、データソースがますます複雑になると、従来の同期方式は非常に無力になります。

当時、次の選択肢がありました。

  1. プロセス / スレッドプールを維持し、一般的なプロセス / スレッドを使用してリクエストを処理する
  2. Gevent などのサードパーティの coroutine+EventLoop ソリューションを使用する
  3. async/await + asyncio の組み合わせを使用する

まず、1 は私たちにとっては除外されました。理由は非常に単純です。重すぎます。2 も最初は一時的に除外されました。当時、私たちは monkey-patch という見た目があまりにも不明瞭な方法に対して恐怖心を抱いていました。

588d9201f5b14873b0504e3a6ab7b402

したがって、私たちは喜んで 3 を選びました。async/await + asyncio の組み合わせを使用することで

実際、最初の効果は非常に素晴らしかったです。しかし、後でこの操作が実際には大変だと気づくでしょう。

async/await をやめる#

なぜ async/await をやめるのか?#

実際には、いくつかの古い問題があります。

1. コードの感染性#

Python の公式の coroutine 実装は、yield/yield from を基にしたジェネレータの改造です。つまり、入り口から始めて、下に向かって徐々に async/await の方法に従う必要があるということです。したがって、同じプロジェクト内には同期 / 非同期のコードが溢れていると信じてください。信じてください、メンテナンスは災難と言えるでしょう。

2. エコシステムと互換性#

現在の async/await の互換性は本当に頭が痛いものです。現在の async/await の有効範囲は、純粋な Python コードに限定されています。ここで問題があります。私たちがプロジェクトで使用している mysqlclient などの C 拡張など、async/await はカバーできません。

同時に、現時点では、async/await の周辺は本当に大きな問題です。バグがいたるところにあり、修正されない状態です。たとえば、aiohttp の https リンクに関連するリンクリークの問題などです。また、Sanic の混乱した設計構造などもあります。

私たちは新しい技術を調査するとき、通常、新しいものが既存の技術をカバーできるかどうか、その周辺が日常の要件を満たすかどうかを重点的に調査します。現時点では、async/await の周辺はまったく満たしていません。

3. パフォーマンスの問題#

現時点では、PEP 3156 で提案された asyncio は、async/await の公式推奨イベントループです。しかし、現時点では公式の実装には多くの不足があります。たとえば、以前の aiohttp の https リンクのリーク問題は、実際には asyncio の SSL 関連の実装に遡ることができます。したがって、使用するときは、通常、サードパーティのループを選択します。現時点では、サードパーティのループは libuv/libev をベースにした実装方法が主流です。これにより、性能は Gevent と同等またはそれ以下になります(PyFrameObject のメンテナンスコストを回避するために Greenlet があります)。

したがって、私たちの髪のために、現時点では async/await を段階的に退役させることにしました。最も遅くとも今年の年末までに、async/await の廃止を完了します。

代替手段は何ですか?#

現時点では、代替手段として Gevent を使用する準備をしています(はい、それは本当に美味しいです)。

理由は非常に単純です。

  1. 現在、成熟しており、明らかな大きなバグはありません
  2. 周辺の開発が成熟しており、純粋な Python コードには Monkey-Patch を使用して既存のコードを移行でき、C 拡張には豆瓣内部で検証された Greenify があります
  3. 基礎となる Greenlet は、必要に応じてコンテキストのトレースを行うための対応する API を提供しています。

async/await に関する他の話#

まず、async/await は素晴らしいものですが、現在は実用的ではありません。これは、コミュニティが関連する使用方法をさらに探求する必要があるということです。

ここで、多くの人が私に尋ねたいと思うでしょう。「ASGI と Django Channel のようなものについてはどう思いますか?」

まず第一に、ASGI は実際には async/await のために設計されたものではありません。最初の設計思想は、PEP333/PEP3333 WSGI プロトコルがますます複雑なネットワークプロトコルモデルに対応できなくなっている問題を解決するためのものです。そして、Django Channel も同じ問題を解決するために作成され、ASGI の実装です(最初は WebSocket を解決するため?)。これらのソリューションは、Django Channel 2.0 では WebSocket のボードキャストを簡単に実現できるなど、多くの問題を解決していますが、彼らと async/await の関連性は非常に小さいです。

今年の PyCon 2018 で、Django チームのコアメンバーが ASGI と Django Channel 2.0 のサポートについて説明しました。将来的には、Django も対応する可能性があります。しかし、問題は、async/await を使用するとき、現在のエコシステム全体がまだ最も心配され、最も脆弱な点であるということです。

だから、こんにちは async/await、さようなら async/await!

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。