2016-05-26 9 views
17

"के साथ async" हो रही aiohttp के लिए शुरू किया डॉक्स निम्न क्लाइंट उदाहरण दे:अजगर 3.4 में

import asyncio 
import aiohttp 

async def fetch_page(session, url): 
    with aiohttp.Timeout(10): 
     async with session.get(url) as response: 
      assert response.status == 200 
      return await response.read() 

loop = asyncio.get_event_loop() 
with aiohttp.ClientSession(loop=loop) as session: 
    content = loop.run_until_complete(
     fetch_page(session, 'http://python.org')) 
    print(content) 

और वे अजगर 3.4 उपयोगकर्ताओं के लिए निम्नलिखित नोट दे:

आप उपयोग कर रहे हैं पायथन 3.4, कृपया @एसिंक डीसी @ कोराउटिन सजावट के साथ उपज के साथ प्रतीक्षा करें।

अगर मैं इन निर्देशों का पालन मैं:

import aiohttp 
import asyncio 

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(10): 
     async with session.get(url) as response: 
      return (yield from response.text()) 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    with aiohttp.ClientSession(loop=loop) as session: 
     html = loop.run_until_complete(
      fetch(session, 'http://python.org')) 
     print(html) 

बहरहाल, यह नहीं चलेगा, क्योंकि async with अजगर 3.4 में समर्थित नहीं है:

$ python3 client.py 
    File "client.py", line 7 
    async with session.get(url) as response: 
      ^
SyntaxError: invalid syntax 

मैं async with अनुवाद कर सकते हैं कैसे पायथन 3.4 के साथ काम करने के लिए बयान?

उत्तर

12

बस संदर्भ प्रबंधक के रूप में session.get() के परिणाम का उपयोग न करें; इसे सीधे कोरआउट के रूप में उपयोग करें। अनुरोध संदर्भ प्रबंधक कि session.get() का उत्पादन होगा सामान्य रूप से बाहर निकलने पर release the request, लेकिन so does using response.text(), तो आपको लगता है कि यहाँ की अनदेखी कर सकते हैं:

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(10): 
     response = yield from session.get(url) 
     return (yield from response.text()) 

अनुरोध आवरण यहाँ लौटे आवश्यक अतुल्यकालिक विधियों (__aenter__ और __aexit__) नहीं है, वे पाइथन 3.5 का उपयोग नहीं करते समय पूरी तरह से छोड़ा गया (relevant source code देखें)।

आप session.get() कॉल पर पहुंचकर response.text() awaitable, तो आप शायद कनेक्शन जारी करने के लिए वैसे भी एक try:..finally: उपयोग करना चाहते हैं के बीच अधिक बयान है, तो; पाइथन 3.5 रिलीज संदर्भ प्रबंधक भी बंद करता है अगर कोई अपवाद हुआ तो प्रतिक्रिया बंद हो जाती है। क्योंकि एक yield from response.release() यहाँ की जरूरत है, इस अजगर 3.4 से पहले एक संदर्भ प्रबंधक में समझाया नहीं जा सकता:

import sys 

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(10): 
     response = yield from session.get(url) 
     try: 
      # other statements 
      return (yield from response.text()) 
     finally: 
      if sys.exc_info()[0] is not None: 
       # on exceptions, close the connection altogether 
       response.close() 
      else: 
       yield from response.release() 
4

aiohttp के examples 3.4 सिंटेक्स के उपयोग को लागू किया। पर json client example आधार पर अपने कार्य होगा:

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(10): 
     resp = yield from session.get(url) 
     try: 
      return (yield from resp.text()) 
     finally: 
      yield from resp.release() 

Upd:

ध्यान दें कि मार्टिन के समाधान सरल मामलों के लिए काम करेंगे, लेकिन विशिष्ट मामलों में अवांछित व्यवहार को जन्म दे सकती:

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(5): 
     response = yield from session.get(url) 

     # Any actions that may lead to error: 
     1/0 

     return (yield from response.text()) 

# exception + warning "Unclosed response" 

अपवाद के अलावा आपको "अनजान प्रतिक्रिया" चेतावनी भी मिल जाएगी। इससे जटिल ऐप में कनेक्शन रिसाव हो सकता है। आप इस समस्या से बचने होगा यदि आप मैन्युअल resp.release()/resp.close() फोन करता हूँ:

@asyncio.coroutine 
def fetch(session, url): 
    with aiohttp.Timeout(5): 
     resp = yield from session.get(url) 
     try: 

      # Any actions that may lead to error: 
      1/0 

      return (yield from resp.text()) 
     except Exception as e: 
      # .close() on exception. 
      resp.close() 
      raise e 
     finally: 
      # .release() otherwise to return connection into free connection pool. 
      # It's ok to release closed response: 
      # https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/client_reqrep.py#L664 
      yield from resp.release() 

# exception only 

मुझे लगता है कि यह सरकारी उदाहरण (और __aexit__implementation) का पालन करें और resp.release()/resp.close() स्पष्ट रूप से कॉल करने के लिए बेहतर है।

+0

मुझे उन उदाहरणों को इंगित करने के लिए धन्यवाद। मुझे वह नहीं मिला था। – Imran

+2

ध्यान दें कि एक अपवाद के मामले में आप आमतौर पर प्रतिक्रिया * बंद करना चाहते हैं। –

+1

@MartijnPieters धन्यवाद, आप सही हैं। मैंने '_RequestContextManager .__ aexit__' तर्क से मेल खाने के लिए कोड तय किया। –

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