質問

Perf Test Redis + Geventに簡単なコードを書いたばかりのコードを書いて、iSyncがパフォーマンスをどのように役立つかを確認し、パフォーマンスが悪いことを見つけました。これが私のコードです。最初の2行をMORKEYパッチに取り除くと、このコードは「通常の実行」タイミングを表示します。

Ubuntu 12.04 LTS VMでは、のタイミングを見ています

モンキーパッチなし - 54秒 モンキーパッチ付き - 61秒

コード/アプローチに何か問題がありますか?PERFの問題はここにありますか?

#!/usr/bin/python

from gevent import monkey

monkey.patch_all()

import timeit
import redis
from redis.connection import UnixDomainSocketConnection

def UxDomainSocket():
    pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path =    '/var/redis/redis.sock')
    r = redis.Redis(connection_pool = pool)
    r.set("testsocket", 1)
    for i in range(100):
            r.incr('testsocket', 10)
    r.get('testsocket')
    r.delete('testsocket')


print timeit.Timer(stmt='UxDomainSocket()',
 setup='from __main__ import UxDomainSocket').timeit(number=1000)
.

役に立ちましたか?

解決

これは予想されます。

このベンチマークをVMで実行します。このベンチマークは、システムコールのコストが物理ハードウェアよりも高いです。 Geventが有効になっていると、(ePollデバイスを処理するために)システムコールを発生させる傾向があるため、パフォーマンスが低くなります。

スクリプトのストレートを使用してこの点を簡単に確認できます。

GEVENTのない、内側のループは次のようになります。

recvfrom(3, ":931\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, ":941\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
.

Geventを使用すると、次のことが発生します。

recvfrom(3, ":221\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, 0x7b0f04, 4096, 0, 0, 0)    = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(5, EPOLL_CTL_ADD, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
epoll_wait(5, {{EPOLLIN, {u32=3, u64=3}}}, 32, 4294967295) = 1
clock_gettime(CLOCK_MONOTONIC, {2469, 779710323}) = 0
epoll_ctl(5, EPOLL_CTL_DEL, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
recvfrom(3, ":231\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
.

呼び出しがブロックされているとき(EAGAIN)、GEVENTはイベントループに戻ります。そのため、ファイル記述子イベント(EPOLL_WAIT)を待機するために追加の呼び出しが行われます。

この種のベンチマークは、1つのファイル記述子のみがあるため、イベントループシステムの最悪の場合がありますので、待機操作を複数の記述子に照合することはできません。さらに、ASYNC I / Oは、すべてが同期しているため、ここで何も向上することはできません。

Redisの最悪の場合:

  • サーバーへの多くのroundtripsを生成します

  • プールはUxDomainsocket関数で宣言されているため、系統的に(1000回)接続/切断(1000回)を接続します。

    実際にあなたのベンチマークはGevent、Redis、またはRedis-Pyをテストしません:それは2つのプロセス間のピンポンゲームを維持するためのVMの能力を運動します。

    パフォーマンスを向上させたい場合は、次の必要があります。

    • 往復の数を減らす の数を減らす

    • プール全体の永続的なベンチマーク を永続的にする

      次のスクリプトで検討してください。

      #!/usr/bin/python
      
      from gevent import monkey
      monkey.patch_all()
      
      import timeit
      import redis
      from redis.connection import UnixDomainSocketConnection
      
      pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/tmp/redis.sock')
      
      def UxDomainSocket():
          r = redis.Redis(connection_pool = pool)
          p = r.pipeline(transaction=False)
          p.set("testsocket", 1)
          for i in range(100):
              p.incr('testsocket', 10)
          p.get('testsocket')
          p.delete('testsocket')
          p.execute()
      
      print timeit.Timer(stmt='UxDomainSocket()', setup='from __main__ import UxDomainSocket').timeit(number=1000)
      
      .

      このスクリプトでは、私は約3倍の優れたパフォーマンスを得て、Geventを使ってオーバーヘッドをほとんどありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top