यह अपेक्षित है।
आप इस बेंचमार्क को VM पर चलाते हैं, जिस पर सिस्टम कॉल की लागत भौतिक हार्डवेयर की तुलना में अधिक होती है। जब जीवेंट सक्रिय होता है, तो यह अधिक सिस्टम कॉल उत्पन्न करता है (एपोल डिवाइस को संभालने के लिए), इसलिए आप कम प्रदर्शन के साथ समाप्त होते हैं।
आप स्क्रिप्ट पर स्ट्रेस का उपयोग करके इस बिंदु को आसानी से देख सकते हैं।
जीवेंट के बिना, आंतरिक लूप उत्पन्न होता है:
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
जब recvfrom कॉल ब्लॉक हो रही होती है (EAGAIN), तो gevent इवेंट लूप में वापस चला जाता है, इसलिए फ़ाइल डिस्क्रिप्टर इवेंट (epoll_wait) की प्रतीक्षा करने के लिए अतिरिक्त कॉल किए जाते हैं।
कृपया ध्यान दें कि इस प्रकार का बेंचमार्क किसी भी ईवेंट लूप सिस्टम के लिए सबसे खराब स्थिति है, क्योंकि आपके पास केवल एक फ़ाइल डिस्क्रिप्टर है, इसलिए प्रतीक्षा संचालन को कई डिस्क्रिप्टर पर फ़ैक्टराइज़ नहीं किया जा सकता है। इसके अलावा, async I/Os यहाँ कुछ भी सुधार नहीं कर सकता क्योंकि सब कुछ समकालिक है।
यह रेडिस के लिए भी सबसे खराब स्थिति है क्योंकि:
-
यह सर्वर पर कई राउंडट्रिप उत्पन्न करता है
-
यह व्यवस्थित रूप से कनेक्ट/डिस्कनेक्ट (1000 बार) करता है क्योंकि पूल को UxDomainSocket फ़ंक्शन में घोषित किया गया है।
वास्तव में आपका बेंचमार्क 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)
इस स्क्रिप्ट के साथ, मुझे लगभग 3x बेहतर प्रदर्शन मिलता है और गीवेंट के साथ लगभग कोई ओवरहेड नहीं होता है।