2013-03-21 9 views
91

मैं gevents और greenlets के लिए नया हूँ। मुझे उनके साथ काम करने के तरीके पर कुछ अच्छा प्रलेखन मिला, लेकिन किसी ने मुझे औपचारिकता नहीं दी कि मुझे कब और कब ग्रीनलेट का उपयोग करना चाहिए!ग्रीनलेट बनाम। थ्रेड

  • वे वास्तव में क्या अच्छे हैं?
  • क्या यह प्रॉक्सी सर्वर में उपयोग करना अच्छा नहीं है या नहीं?
  • धागे क्यों नहीं?

मुझे इस बारे में निश्चित नहीं है कि वे मूल रूप से सह-रूटीन होने पर हमें समवर्तीता प्रदान कर सकते हैं।

+1

@Imran यह जावा में greenthreads के बारे में है का उपयोग कर आई/ओ में कुछ महत्वपूर्ण अंतर है। मेरा सवाल पाइथन में ग्रीनलेट के बारे में है। क्या मैं कुछ भूल रहा हूँ ? – Rsh

+0

अफैइक, पाइथन में धागे वास्तव में वैश्विक दुभाषिया ताला के कारण वास्तव में समवर्ती नहीं हैं। तो यह दोनों समाधानों के ऊपरी हिस्से की तुलना करने के लिए उबाल जाएगा। हालांकि मैं समझता हूं कि पाइथन के कई कार्यान्वयन हैं, इसलिए यह उन सभी के लिए लागू नहीं हो सकता है। – didierc

+3

@didierc CPython (और अभी तक पीपीपीई) समानांतर * में पाइथन (बाइट) कोड * की व्याख्या नहीं करेगा (यानी, वास्तव में शारीरिक रूप से दो अलग-अलग CPU कोरों पर)। हालांकि, जीआईएल के तहत एक पायथन कार्यक्रम नहीं है (सामान्य उदाहरण आई/ओ और सी कार्यों सहित सिस्कोल हैं जो जानबूझकर जीआईएल जारी करते हैं), और 'थ्रेडिंग। थ्रेड' वास्तव में सभी रैमिकेशंस के साथ एक ओएस थ्रेड है। तो यह वास्तव में इतना आसान नहीं है। वैसे, ज्योथन के पास कोई गिला AFAIK नहीं है और पीपीपी भी इससे छुटकारा पाने की कोशिश कर रहा है। – delnan

उत्तर

142

ग्रीनलेट समेकन प्रदान करते हैं लेकिन समांतरता प्रदान नहीं करते हैं। Concurrency तब होता है जब कोड अन्य कोड से स्वतंत्र रूप से चलाया जा सकता है। समांतरता एक साथ समवर्ती कोड का निष्पादन है। समांतरता विशेष रूप से उपयोगी होती है जब उपयोगकर्तास्थान में बहुत सारे काम किए जाते हैं, और यह आमतौर पर सीपीयू-भारी सामान होता है। Concurrency अलग-अलग समस्याओं को तोड़ने के लिए उपयोगी है, जिससे विभिन्न हिस्सों को निर्धारित किया जा सकता है और समानांतर में अधिक आसानी से प्रबंधित किया जा सकता है।

ग्रीनलेट वास्तव में नेटवर्क प्रोग्रामिंग में चमकते हैं जहां एक सॉकेट के साथ बातचीत अन्य सॉकेट के साथ बातचीत के स्वतंत्र रूप से हो सकती है। यह समवर्तीता का एक उत्कृष्ट उदाहरण है। चूंकि प्रत्येक ग्रीनलेट अपने संदर्भ में चलता है, इसलिए आप थ्रेडिंग के बिना सिंक्रोनस एपीआई का उपयोग करना जारी रख सकते हैं। यह अच्छा है क्योंकि वर्चुअल मेमोरी और कर्नेल ओवरहेड के मामले में धागे बहुत महंगा हैं, इसलिए थ्रेड के साथ प्राप्त समेकन काफी कम है। इसके अतिरिक्त, पाइथन में थ्रेडिंग अधिक महंगा है और जीआईएल के कारण सामान्य से अधिक सीमित है। समेकन के विकल्प आमतौर पर ट्विस्ट, libevent, libuv, node.js आदि जैसी परियोजनाएं होती हैं, जहां आपका सभी कोड समान निष्पादन संदर्भ साझा करता है, और ईवेंट हैंडलर पंजीकृत करता है।

प्रॉक्सी लिखने के लिए ग्रीनलेट्स (उचित नेटवर्किंग समर्थन जैसे भूगर्भ के माध्यम से) का उपयोग करना एक उत्कृष्ट विचार है, क्योंकि अनुरोधों का प्रबंधन स्वतंत्र रूप से निष्पादित करने में सक्षम है और इसे इस तरह लिखा जाना चाहिए।

ग्रीनलेट पहले दिए गए कारणों के लिए सहमति प्रदान करते हैं। Concurrency समानांतरता नहीं है। इवेंट पंजीकरण छुपाकर और उन कॉलों पर आपके लिए समय-सारिणी निष्पादित करके जो सामान्य थ्रेड को अवरुद्ध करेंगे, गीवेन्ट जैसी परियोजनाएं इस समेकन को एक एसिंक्रोनस एपीआई में बदलने की आवश्यकता के बिना, और आपके सिस्टम पर काफी कम लागत के बिना प्रकट करती हैं।

+1

धन्यवाद, केवल दो छोटे प्रश्न: 1) क्या उच्च समाधान प्राप्त करने के लिए मल्टीप्रोसेसिंग के साथ इस समाधान को गठबंधन करना संभव है? 2) मुझे अभी भी पता नहीं है कि कभी थ्रेड का उपयोग क्यों करते हैं? क्या हम उन्हें पायथन मानक पुस्तकालय में समरूपता के निष्पक्ष और बुनियादी कार्यान्वयन के रूप में मान सकते हैं? – Rsh

+6

1) हां, बिल्कुल। आपको इसे समय से पहले नहीं करना चाहिए, लेकिन इस प्रश्न के दायरे से परे कारकों के पूरे समूह की वजह से, कई प्रक्रियाओं के अनुरोध से आपको उच्च थ्रूपुट मिलेगा। 2) ओएस धागे preemptively निर्धारित हैं, और डिफ़ॉल्ट रूप से पूरी तरह से समानांतर। वे पाइथन में डिफ़ॉल्ट हैं क्योंकि पायथन मूल थ्रेडिंग इंटरफ़ेस का खुलासा करता है, और थ्रेड आधुनिक ऑपरेटिंग सिस्टम में समांतरता और समरूपता दोनों के लिए सबसे अच्छा समर्थित और सबसे कम आम denominator हैं। –

+6

मुझे यह उल्लेख करना चाहिए कि आपको तब तक ग्रीनलेट्स का उपयोग नहीं करना चाहिए जब तक कि धागे संतोषजनक न हों (आमतौर पर यह आपके द्वारा संभाले जाने वाले एक साथ कनेक्शन की संख्या के कारण होता है, और धागा गिनती या जीआईएल आपको दुःख दे रहा है), और तब भी तभी होगा जब आपके लिए कुछ अन्य विकल्प उपलब्ध न हो। पाइथन मानक पुस्तकालय, और अधिकांश तीसरे पक्ष के पुस्तकालय * उम्मीद * थ्रेड के माध्यम से समेकन प्राप्त करने की अपेक्षा करते हैं, इसलिए यदि आप इसे हरितलेट के माध्यम से प्रदान करते हैं तो आपको अजीब व्यवहार मिल सकता है। –

10

यह काफी दिलचस्प विश्लेषण करने के लिए है। यहाँ बनाम बहु सूत्रण पूल बहु बनाम greenlets के प्रदर्शन की तुलना करने के लिए एक कोड है:

Using gevent it took: 0.083758 
----------- 
Using multiprocessing it took: 0.023633 
----------- 
Using multi-threading it took: 0.008327 

मुझे लगता है कि greenlet का दावा है कि यह है कि यह विपरीत Gil द्वारा बाध्य नहीं है:

import gevent 
from gevent import socket as gsock 
import socket as sock 
from multiprocessing import Pool 
from threading import Thread 
from datetime import datetime 

class IpGetter(Thread): 
    def __init__(self, domain): 
     Thread.__init__(self) 
     self.domain = domain 
    def run(self): 
     self.ip = sock.gethostbyname(self.domain) 

if __name__ == "__main__": 
    URLS = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org'] 
    t1 = datetime.now() 
    jobs = [gevent.spawn(gsock.gethostbyname, url) for url in URLS] 
    gevent.joinall(jobs, timeout=2) 
    t2 = datetime.now() 
    print "Using gevent it took: %s" % (t2-t1).total_seconds() 
    print "-----------" 
    t1 = datetime.now() 
    pool = Pool(len(URLS)) 
    results = pool.map(sock.gethostbyname, URLS) 
    t2 = datetime.now() 
    pool.close() 
    print "Using multiprocessing it took: %s" % (t2-t1).total_seconds() 
    print "-----------" 
    t1 = datetime.now() 
    threads = [] 
    for url in URLS: 
     t = IpGetter(url) 
     t.start() 
     threads.append(t) 
    for t in threads: 
     t.join() 
    t2 = datetime.now() 
    print "Using multi-threading it took: %s" % (t2-t1).total_seconds() 
यहाँ

परिणाम हैं multithreading पुस्तकालय। इसके अलावा, ग्रीनलेट डॉक्टर का कहना है कि यह नेटवर्क संचालन के लिए है। नेटवर्क गहन ऑपरेशन के लिए, थ्रेड-स्विचिंग ठीक है और आप देख सकते हैं कि मल्टीथ्रेडिंग दृष्टिकोण बहुत तेज़ है। यह भी हमेशा पाइथन के आधिकारिक पुस्तकालयों का उपयोग करने के लिए prefeerable है; मैंने विंडोज़ पर ग्रीनलेट स्थापित करने की कोशिश की और एक डीएल निर्भरता समस्या का सामना किया, इसलिए मैंने इस परीक्षण को लिनक्स वीएम पर चलाया। हमेशा किसी भी मशीन पर चलने वाली उम्मीद के साथ एक कोड लिखने का प्रयास करें।

+17

ध्यान दें कि 'getockbyname' 'ओएस स्तर पर परिणाम कैश करता है (कम से कम मेरी मशीन पर यह करता है)। जब पहले अज्ञात या कालबाह्य DNS पर आक्रमण किया जाता है तो यह वास्तव में एक नेटवर्क क्वेरी करेगा, जिसमें कुछ समय लग सकता है। जब किसी मेजबाननाम पर हाल ही में हल किया गया है, तो यह जवाब बहुत तेज़ी से वापस कर देगा। नतीजतन, आपकी माप पद्धति यहां त्रुटिपूर्ण है। यह आपके अजीब परिणामों को बताता है - गीवेंट वास्तव में मल्टीथ्रेडिंग की तुलना में इतना बुरा नहीं हो सकता है - दोनों वीएम स्तर पर वास्तव में समानांतर नहीं हैं। –

+0

@ केटी। यह एक उत्कृष्ट बिंदु है। आपको एक अच्छी तस्वीर पाने के लिए कई बार परीक्षण करना होगा और साधन, मोड और मध्यस्थों को लेना होगा। ध्यान दें कि राउटर प्रोटोकॉल के लिए रूट पथ कैश करते हैं और जहां वे रूट पथ कैश नहीं करते हैं, तो आप विभिन्न डीएनएस मार्ग पथ यातायात से अलग अंतराल प्राप्त कर सकते हैं। और डीएनएस सर्वर भारी कैश। Time.clock() का उपयोग करके थ्रेडिंग को मापना बेहतर हो सकता है जहां नेटवर्क हार्डवेयर पर विलंबता से प्रभावित होने के बजाय सीपीयू चक्र का उपयोग किया जाता है। इससे आपके ओएस सेवाओं में घुसपैठ और आपके माप से समय जोड़ना समाप्त हो सकता है। – DevPlayer

+0

ओह और आप उन तीन परीक्षणों के बीच ओएस स्तर पर एक डीएनएस फ्लश चला सकते हैं लेकिन फिर से यह स्थानीय डीएनएस कैशिंग से केवल झूठे डेटा को कम करेगा। – DevPlayer

18

मैक्स के उत्तर को लेना और स्केलिंग के लिए इसमें कुछ प्रासंगिकता जोड़ना, आप अंतर देख सकते हैं। मैं इस प्रकार भरे जाने वाले URL को बदलने कर यह उपलब्धि हासिल:

URLS_base = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org'] 
URLS = [] 
for _ in range(10000): 
    for url in URLS_base: 
     URLS.append(url) 

मैं के रूप में यह गिर गया इससे पहले कि मैं 500 था मल्टीप्रोसेस संस्करण बाहर छोड़ना पड़ा; लेकिन 10,000 पुनरावृत्तियों में:

Using gevent it took: 3.756914 
----------- 
Using multi-threading it took: 15.797028 

तो आप देख सकते वहाँ gevent

संबंधित मुद्दे