Dies wird erwartet.
Sie führen diesen Benchmark auf einer VM aus, auf der die Kosten für Systemaufrufe höher sind als auf physischer Hardware. Wenn gevent aktiviert ist, erzeugt es tendenziell mehr Systemaufrufe (um das epoll-Gerät zu handhaben), so dass Sie weniger Leistung haben.
Sie können diesen Punkt leicht überprüfen, indem Sie strace im Skript verwenden.
Ohne GEVENT, die innere Schleife erzeugt:
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
Mit GEVENT, haben Sie Vorkommen von:
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
Wenn der Recvfrom Anruf (EAGAIN) blockiert, GEVENT geht an die Rückseite Ereignisschleife, so dass zusätzliche Aufrufe ausgeführt werden, um auf Dateibeschreibungs-Ereignisse (epoll_wait) zu warten.
Bitte beachten Sie, dass diese Art von Benchmark ein Worst Case für jedes Ereignisschleifensystem ist, da Sie nur einen Dateideskriptor haben, so dass die Warteoperationen nicht auf mehrere Deskriptoren faktorisiert werden können. Darüber hinaus können Async-I/Os hier nichts verbessern, da alles synchron ist.
Es ist auch eine Worst-Case für Redis, weil:
es viele Roundtrips zum Server
verbindet erzeugt systematisch/trennt (1000-mal), da der Pool in UxDomainSocket Funktion deklariert wird .
Eigentlich ist Ihre Benchmark nicht testen GEVENT, redis oder redis-py: es übt die Fähigkeit einer VM ein Ping-Pong-Spiel zwischen zwei Prozessen zu unterstützen.
Wenn Sie die Leistung erhöhen wollen, müssen Sie:
Betrachten Sie zum Beispiel das folgende Skript:
#!/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)
Mit diesem Skript bekomme ich etwa 3x bessere Leistung und fast keinen Overhead mit gevent.
Danke für die ausführliche Antwort. Wenn ich das tiefere Problem im Grunde verstehe, was ich getan habe, ist, dass es nur ein "Objekt" gibt, auf das gewartet werden kann - wenn ich zum Beispiel einen Pool von Redis-Verbindungen hatte und ich gevent verwende, dann würde es mir die bessere Leistung geben redis kann mithalten). BTW die VM (und Ux-Buchse) war nur zum Testen. Produktion wird verschiedene Instanzen usw., – vivekv
wenn Pipeline verwendet wird, dann wie "Redis Sperre" verwenden – Tallmad