To jest oczekiwane.
Ten test porównawczy jest uruchamiany na maszynie wirtualnej, na której koszt wywołań systemowych jest wyższy niż na sprzęcie fizycznym. Kiedy gevent jest aktywowany, ma tendencję do generowania większej liczby wywołań systemowych (w celu obsługi urządzenia epoll), dzięki czemu uzyskuje się mniejszą wydajność.
Możesz łatwo sprawdzić ten punkt, używając strace w skrypcie.
Bez gevent, wewnętrzna pętla generuje:
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
Z gevent, trzeba będzie wystąpień:
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
Kiedy rozmowa recvfrom blokuje (EAGAIN) gevent sięga pętli zdarzeń, więc wykonywane są dodatkowe wywołania, aby czekać na zdarzenia deskryptorów plików (epoll_wait).
Należy zwrócić uwagę, że ten rodzaj testu porównawczego jest najgorszym przypadkiem dla dowolnego systemu pętli zdarzeń, ponieważ istnieje tylko jeden deskryptor pliku, więc operacje oczekiwania nie mogą być uwzględniane w kilku deskryptorach. Ponadto asynchroniczne operacje we/wy nie mogą niczego poprawić, ponieważ wszystko jest synchroniczne.
Jest to również najgorszy przypadek Redis, ponieważ:
generuje wiele roundtrips do serwera
systematycznie łączy/rozłącza (1000 razy), ponieważ basen jest zadeklarowana w funkcji UxDomainSocket .
Właściwie Twój odniesienia nie testuje gevent, Redis lub Redis-Py: sprawowanej zdolność VM aby utrzymać grę ping-pong między 2 procesów.
Jeśli chcesz, aby zwiększyć wydajność, trzeba:
Na przykład rozważmy poniższy skrypt:
#!/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)
Dzięki temu skryptowi uzyskuję około 3 razy lepszą wydajność i prawie żadnych kosztów ogólnych przy użyciu gevent.
Dzięki za szczegółową odpowiedź. Jeśli rozumiem głębszy problem, w zasadzie to, co zrobiłem, to to, że istnieje tylko jeden "obiekt", na który można czekać - jeśli na przykład miałem pulę połączeń Redis i używam geventa, to dałbym mi lepszą wydajność (zakładając redis może nadążyć). BTW VM (i gniazdo Ux) służy wyłącznie do testowania. Produkcją będą inne instancje itp., – vivekv
jeśli używany jest potok, to jak używać "blokady redis" – Tallmad