私はgeventsとgreenletsに不慣れです。私はそれらをどのように扱うかについていくつかの良い文書を見つけましたが、私がグリーンレットをいつどのように使うべきかについての正当化を私に与えてくれませんでした!
- 彼らは本当に何が得意ですか?
- プロキシサーバーで使用するのは良い考えですか?
- なぜスレッドしないのですか?
私がよくわからないのは、基本的にコルーチンである場合に、どのように並行性を提供できるかということです。
私はgeventsとgreenletsに不慣れです。私はそれらをどのように扱うかについていくつかの良い文書を見つけましたが、私がグリーンレットをいつどのように使うべきかについての正当化を私に与えてくれませんでした!
私がよくわからないのは、基本的にコルーチンである場合に、どのように並行性を提供できるかということです。
Greenlet は並行処理を提供しますが、並列処理は提供しません。並行性とは、コードが他のコードから独立して実行できる場合です。並列処理とは、並行コードを同時に実行することです。並列処理は、ユーザー空間で実行する作業が多く、通常は CPU を大量に使用する場合に特に役立ちます。並行性は問題を分割するのに役立ち、さまざまな部分をより簡単に並行してスケジュールおよび管理できるようにします。
Greenlet は、1 つのソケットとの対話が他のソケットとの対話とは独立して発生できるネットワーク プログラミングで真価を発揮します。これは並行性の典型的な例です。各 greenlet は独自のコンテキストで実行されるため、スレッド化せずに同期 API を引き続き使用できます。スレッドは仮想メモリとカーネルのオーバーヘッドの点で非常に高価であるため、これは良いことです。そのため、スレッドで実現できる同時実行性は大幅に低下します。さらに、Python でのスレッド化は、GIL のために、通常よりもコストがかかり、より制限されています。コンカレンシーの代替は通常、Twisted、libevent、libuv、node.js などのプロジェクトであり、すべてのコードが同じ実行コンテキストを共有し、イベント ハンドラーを登録します。
リクエストの処理は独立して実行することができ、そのように書かれるべきであるため、プロキシを書くために (gevent などの適切なネットワーク サポートを備えた) greenlet を使用することは優れた考えです。
Greenlet は、先に述べた理由で並行性を提供します。同時実行は並列処理ではありません。イベント登録を隠し、通常は現在のスレッドをブロックする呼び出しでスケジューリングを実行することにより、gevent のようなプロジェクトは、非同期 API を変更する必要なく、システムのコストを大幅に削減して、この同時実行性を公開します。
これは分析するのに十分興味深いものです。greenlet とマルチプロセッシング プールとマルチスレッドのパフォーマンスを比較するコードを次に示します。
import gevent
from gevent import socket as gsock
import socket as sock
from multiprocessing import Pool
from threading import Thread
from datetime import datetime
class IpGetter(Thread):
def __init__(self, domain):
Thread.__init__(self)
self.domain = domain
def run(self):
self.ip = sock.gethostbyname(self.domain)
if __name__ == "__main__":
URLS = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
t1 = datetime.now()
jobs = [gevent.spawn(gsock.gethostbyname, url) for url in URLS]
gevent.joinall(jobs, timeout=2)
t2 = datetime.now()
print "Using gevent it took: %s" % (t2-t1).total_seconds()
print "-----------"
t1 = datetime.now()
pool = Pool(len(URLS))
results = pool.map(sock.gethostbyname, URLS)
t2 = datetime.now()
pool.close()
print "Using multiprocessing it took: %s" % (t2-t1).total_seconds()
print "-----------"
t1 = datetime.now()
threads = []
for url in URLS:
t = IpGetter(url)
t.start()
threads.append(t)
for t in threads:
t.join()
t2 = datetime.now()
print "Using multi-threading it took: %s" % (t2-t1).total_seconds()
結果は次のとおりです。
Using gevent it took: 0.083758
-----------
Using multiprocessing it took: 0.023633
-----------
Using multi-threading it took: 0.008327
greenlet は、マルチスレッド ライブラリとは異なり、GIL に拘束されないと主張していると思います。さらに、Greenlet doc は、ネットワーク操作を目的としていると述べています。ネットワークを集中的に使用する操作の場合、スレッド切り替えは問題なく、マルチスレッド アプローチがかなり高速であることがわかります。また、常に Python の公式ライブラリを使用することをお勧めします。Windows に greenlet をインストールしようとしたところ、dll の依存関係の問題が発生したため、Linux vm でこのテストを実行しました。どのマシンでも実行できることを常に期待してコードを記述してください。