2015-10-26 10 views
7

मुझे पाइथन 3.5 में asyncio का उपयोग करने का प्रवाह मिल रहा है, लेकिन मैंने यह नहीं देखा है कि मुझे क्या करना चाहिए await आईएनजी और चीजें जो मुझे नहीं होनी चाहिए या जहां यह लचीला होगा। क्या मुझे सिर्फ "आईओ ऑपरेशन है और इस प्रकार await एड होना चाहिए" के संदर्भ में मेरा सबसे अच्छा निर्णय लेना है?जब पाइथन 3.5 'प्रतीक्षा' का उपयोग नहीं किया जाए और कब उपयोग किया जाए?

+4

विवरण के लिए [पीईपी 492] (https://www.python.org/dev/peps/pep-0492/#id50) पढ़ें, लेकिन आमतौर पर आपको सभी वायदा पर 'प्रतीक्षा' करना चाहिए, @ कोराउटिन 'सजाए गए कार्यों और 'async def' फ़ंक्शंस। –

उत्तर

17

डिफ़ॉल्ट रूप से आपका सभी कोड तुल्यकालिक है। आप इसे async def के साथ एसिंक्रोनस परिभाषित फ़ंक्शंस बना सकते हैं और await के साथ इस फ़ंक्शन को कॉल कर सकते हैं। अधिक सही सवाल यह है कि "मुझे सिंक्रोनस के बजाय एसिंक्रोनस कोड कब लिखना चाहिए?"। जवाब है "जब आप इसका लाभ उठा सकते हैं"। ज्यादातर मामलों में के रूप में आप का उल्लेख किया आप लाभ भी मिलेगा, जब आप मैं के साथ काम/ओ संचालन:

# Synchronous way: 
download(url1) # takes 5 sec. 
download(url2) # takes 5 sec. 
# Total time: 10 sec. 

# Asynchronous way: 
await asyncio.gather(
    download(url1), # takes 5 sec. 
    download(url2) # takes 5 sec. 
) 
# Total time: only 5 sec. (+ little overhead for using asyncio) 
बेशक

, यदि आप समारोह एसिंक्रोनस कोड का उपयोग करता है, इस समारोह भी अतुल्यकालिक होना चाहिए बनाया (के रूप में परिभाषित किया जाना चाहिए async def)। लेकिन कोई भी एसिंक्रोनस फ़ंक्शन स्वतंत्र रूप से सिंक्रोनस कोड का उपयोग कर सकता है। यह किसी कारण के बिना अतुल्यकालिक तुल्यकालिक कोड कास्ट करने के लिए कोई मतलब नहीं है:

# extract_links(url) should be async because it uses async func download() inside 
async def extract_links(url): 
    # download() was created async to get benefit of I/O 
    data = await download(url) 
    # parse() doesn't work with I/O, no sense to make it async 
    links = parse(data) 
    return links 

एक बहुत महत्वपूर्ण बात यह है कि किसी भी लंबे तुल्यकालिक आपरेशन (> 50 एमएस, उदाहरण के लिए, यह मुश्किल वास्तव में कहने के लिए है) है अपने सभी अतुल्यकालिक फ्रीज होगा उस समय के लिए संचालन:

async def extract_links(url): 
    data = await download(url) 
    links = parse(data) 
    # if search_in_very_big_file() takes much time to process, 
    # all your running async funcs (somewhere else in code) will be friezed 
    # you need to avoid this situation 
    links_found = search_in_very_big_file(links) 

आप इसे लंबे बुला अलग प्रक्रिया में तुल्यकालिक कार्यों चल रहा है (और परिणाम के लिए इंतजार कर रहा) से बच सकते हैं:

executor = ProcessPoolExecutor(2) 

async def extract_links(url): 
    data = await download(url) 
    links = parse(data) 
    # Now your main process can handle another async functions while separate process running  
    links_found = await loop.run_in_executor(executor, search_in_very_big_file, links) 

एक और उदाहरण: जब आपको एसिन्सीओ में requests का उपयोग करने की आवश्यकता है। requests.get सिंक्रोनस लम्बी चलने वाली फ़ंक्शन है, जिसे आपको एसिंक कोड (फिर से, ठंड से बचने के लिए) के अंदर कॉल नहीं करना चाहिए। लेकिन यह लंबी गणनाओं के कारण नहीं, I/O की वजह से लंबा चल रहा है। उस मामले में, आप कुछ बहु भूमि के ऊपर से बचने के लिए ThreadPoolExecutor बजाय ProcessPoolExecutor उपयोग कर सकते हैं:

executor = ThreadPoolExecutor(2) 

async def download(url): 
    response = await loop.run_in_executor(executor, requests.get, url) 
    return response.text 
+0

देर से उत्तर की पुष्टि के लिए खेद है। स्पष्टीकरण के लिए धन्यवाद, इससे मुझे बहुत मदद मिली! – dalanmiller

-1

तुम बहुत स्वतंत्रता नहीं है। यदि आपको किसी फ़ंक्शन को कॉल करने की आवश्यकता है तो आपको यह पता लगाना होगा कि यह सामान्य कार्य है या कोरआउट है। आपको await कीवर्ड का उपयोग करना चाहिए यदि केवल और यदि आप जिस फ़ंक्शन को कॉल कर रहे हैं वह कोरआउट है।

यदि async फ़ंक्शंस शामिल हैं तो "इवेंट लूप" होना चाहिए जो इन async फ़ंक्शंस को ऑर्केस्ट्रेट करता है। कड़ाई से बोलना जरूरी नहीं है, आप async विधि को मैन्युअल रूप से भेजने के तरीके को "मैन्युअल रूप से" चला सकते हैं, लेकिन शायद आप इसे नहीं करना चाहते हैं। इवेंट लूप अभी तक समाप्त नहीं हुआ कोरआउटिन का ट्रैक रखता है और अगले को जारी रखने के लिए चुनता है। asyncio मॉड्यूल इवेंट लूप का कार्यान्वयन प्रदान करता है, लेकिन यह एकमात्र संभव कार्यान्वयन नहीं है।

x = get_x() 
do_something_else() 

और

x = await aget_x() 
do_something_else() 

अर्थ बिल्कुल एक ही है:

कोड की इन दो पंक्तियों पर विचार करें, एक तरीका है जिसके कुछ मूल्य का उत्पादन फोन जब मूल्य चर x के लिए असाइन करें तैयार है और कुछ और करो। दोनों मामलों में do_something_else फ़ंक्शन को कोड की पिछली पंक्ति समाप्त होने के बाद ही कॉल किया जाएगा।इसका मतलब यह भी नहीं है कि एसिंक्रोनस aget_x विधि के निष्पादन के पहले या बाद में विधि इवेंट लूप पर नियंत्रण प्रदान किया जाएगा।

फिर भी वहाँ कुछ मतभेद हैं:

  • दूसरा टुकड़ा केवल एक और async समारोह
  • aget_x समारोह सामान्य नहीं है अंदर प्रकट हो सकते हैं, लेकिन coroutine (है कि या तो async कीवर्ड के साथ घोषणा की है या coroutine के रूप में सजाया गया है)
  • aget_x इवेंट लूप के साथ "संवाद" करने में सक्षम है: यह कुछ वस्तुओं को उत्पन्न करता है। इवेंट लूप इन ऑब्जेक्ट्स को कुछ परिचालन करने के अनुरोध के रूप में समझने में सक्षम होना चाहिए (उदाहरण के लिए नेटवर्क अनुरोध भेजने और प्रतिक्रिया के लिए प्रतीक्षा करें, या n सेकेंड के लिए इस कोरआउट को निलंबित करें)। सामान्य get_x फ़ंक्शन इवेंट लूप के साथ संवाद करने में सक्षम नहीं है।
संबंधित मुद्दे

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