2015-01-11 12 views
5

まず、私の悪い英語を申し訳ありません。 私のプロジェクトでは、たくさんのI/Oネットワーク要求があります。メインデータは別のプロジェクトに保存され、アクセスはWeb API(JSON/XML)、ポーリングによって提供されます。新しいユーザーセッションごとにこのAPIを使用します(ユーザーに関する情報を取得する)。そして時々、私たちは応答を待つことに問題があります。 nginx + uwsgi + djangoを使用します。ご存知のように、Djangoは同期(またはブロック)しています。 ネットワークIO待機の問題を解決するために、マルチスレッドでuwsgiを使用します。 私はgeventについて読むことに決めました。私は、協調と先制マルチタスクの違いを理解しています。そして、この問題(ネットワークI/Oボトルネック)のために、geventがuwsgiスレッドより優れた解決策であることを期待しました。しかし、結果はほぼ同じでした。ときどきgeventは弱かった。 多分私は間違っています。教えてください。ジヴェントとスレッドのUwsgi

ここにuwsgiの設定例があります。 Gevent:

$ uwsgi --http :8001 --module ugtest.wsgi --gevent 40 --gevent-monkey-patch 

スレッディング:

$ uwsgi --http :8001 --module ugtest.wsgi --enable-threads --threads 40 

コントローラ例:

def simple_test_action(request): 
    # get data from API without parsing (only for simple I/O test) 
    data = _get_data_by_url(API_URL) 
    return JsonResponse(data, safe=False) 

import httplib 
from urlparse import urlparse 
def _get_data_by_url(url): 
    u = urlparse(url) 
    if str(u.scheme).strip().lower() == 'https': 
     conn = httplib.HTTPSConnection(u.netloc) 
    else: 
     conn = httplib.HTTPConnection(u.netloc) 
    path_with_params = '%s?%s' % (u.path, u.query,) 
    conn.request("GET", path_with_params) 
    resp = conn.getresponse() 
    print resp.status, resp.reason 
    body = resp.read() 
    return body 

geventhttpclient付き)試験:

def get_info(i): 
    url = URL('http://localhost:8001/simpletestaction/') 
    http = HTTPClient.from_url(url, concurrency=100, connection_timeout=60, network_timeout=60) 
    try: 
     response = http.get(url.request_uri) 
     s = response.status_code 
     body = response.read() 
    finally: 
     http.close() 


dt_start = dt.now() 
print 'Start: %s' % dt_start 

threads = [gevent.spawn(get_info, i) for i in xrange(401)] 
gevent.joinall(threads) 
dt_end = dt.now() 

print 'End: %s' % dt_end 
print dt_end-dt_start 

どちらの場合も私は似たような時があります。同様の問題(APIプロキシミング)の中でgeent/greenletsとcooperativeマルチタスクの利点は何ですか?

答えて

5

同時実行性は、geventが輝くようなレベルではありません。 Geventは並列性(または要求ごとのパフォーマンス)ではないため、並行性の「低」レベルを持つことは改善のための良い方法ではありません。

は、一般的に、あなたは(GILは、I/Oの際に放出される)、geventの利点がある悪くはないではない40 :)

I/OのPythonのスレッドをブロックするために、何千ものレベルとgevent同時実行が表示されますリソース使用量(1000のpythonスレッドを持つことは過剰です)とロックと友人について考える必要性の除去。

もちろん、django(デフォルトでは)ではチューニングが少し必要です(データベースアダプタをgeentに変更する必要があります)。

+0

私はスレッド/ greenletsの別の数でそれをテストしようとしています。何千人も、何百人もありません。結果は似ています。 コントローラのアクション(join()/ joinall()を使用)で複数のリクエストがある場合、geventは最良の選択です。 しかし、私の問題(「プロキシ」-API)には大きなメリットがありません。 最初のケース(スレッド)には簡単な設定があります:--threads N. 2番目のケース(gevent)では、postgresドライバ(redisなど)にパッチを当てることに多くの問題があります。完全なスタックトレースの問題... – OLMER

+0

あなたが "パッチ" djangoできない場合、申し訳ありませんが、あなたに従うことはできません、あなたgevent、thats'itを使用することはできません。あなたのアプリは100%ノンブロッキングでなければなりません。そうでなければ、それはブロックアプリであり、geventはあなたを助けません(よく、最悪の場合もあります) – roberto

1

サービングノンブロッキングはパフォーマンスに関してではなく、並行性に関するものです。要求時間の99%がサブリクエストで費やされている場合、それらの99%を最適化することはできません。しかし、使用可能なすべてのスレッドがビジーになると、新しいクライアントは拒否されますが、スレッドの時間の99%がサブ要求の完了を待つのに費やされます。ノンブロッキングサービングでは、利用可能なスレッドの数によって制限されていない「ハンドラ」間で共有することで、そのアイドル時間を利用できます。したがって、99%が待機している場合、もう1%はCPUバインド処理なので、CPUを最大限に使う前に100倍多くの接続を同時に行うことができます.100倍以上のスレッドを必要とせず、高価になります(PythonのGILより高価なサブプロセスを使用する必要があります)。

ロベルト氏によると、アイドル時間を救済するには、コードは100%ノンブロッキングでなければなりません。ただし、上記のパーセント値からわかるように、要求がほぼ完全にIOバインドされている場合にのみ重要になります。そうであれば、少なくともあなたのアプリの部分ではDjangoは必要ないでしょう。

関連する問題