2016-05-26 32 views
17

"ile zaman uyumsuz" aiohttp için Başlangıç ​​dokümanlar aşağıdaki istemci örnek vermek Alma:Python 3.4'te

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) 

Ve onlar Python 3.4 kullanıcıları için aşağıdaki notu vermek: Eğer kullanıyorsanız

Python 3.4, lütfen @coroutine dekolayıcısından async def ile beklemeden bekleyiniz. Ben bu talimatları izlerseniz

alıyorum:

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) 

Ancak bu yayınlanmaz, async with Python 3.4 desteklenmediği için:

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

Ben async with çevirebilir nasıl Python 3.4 ile çalışmak için açıklama?

cevap

12

Sadece içerik yöneticisi olarak session.get() sonucunu kullanmayın; Bunun yerine doğrudan bir koroutin olarak kullanın. istek bağlam yöneticisi session.get() ürettiğini normalde Çıkışta release the request ancak so does using response.text() olur, bu nedenle burada göz ardı olabilir:

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

sarıcı burada dönen taleplerini bildirmeleri gerekmektedir asenkron yöntemleri (__aenter__ ve __aexit__) yoktur, onlar Python 3.5 kullanılmadığında tamamen atlanmıştır (bkz. relevant source code).

Eğer session.get() çağrı ve, muhtemelen bağlantıyı serbest bırakmak için yine bir try:..finally: kullanmak awaitable istiyorum response.text() erişmek arasındaki daha ifadeleri varsa; Python 3.5 sürüm bağlam yöneticisi ayrıca bir özel durum oluştuğunda yanıtı kapatır. Bir yield from response.release() burada gerekli olduğundan, bu Python 3.4 önce bir bağlam yöneticisinde kapsüllü edilemez:

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 'ın examples 3.4 sözdizimi kullanılarak uygulanır. json client example dayanarak sizin fonksiyonu olacaktır:

@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" 

: Martijn çözümü basit durumlar için çalışacak, ancak belirli durumlarda istenmeyen davranışlara yol açabileceğini

Not İstisna dışında, "Kapatılmamış cevap" uyarısı da alacaksınız. Bu, karmaşık uygulamada bağlantıların sızmasına neden olabilir. el resp.release()/resp.close() diyeceğiz bu sorunu önlemek olacaktır:

@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 

bunun resmi örnekleri uygulayın (ve __aexit__implementation) ve açıkça resp.release()/resp.close() aramak daha olduğunu düşünüyorum.

+0

Bu örneklere işaret ettiğiniz için teşekkür ederiz. Ben bunları bulamadım. – Imran

+2

Bir istisna durumunda, genellikle yanıtı * kapatmak istediğinizi unutmayın. –

+1

@MartijnPieters teşekkürler, haklısınız. Kodu _RequestContextManager .__ aexit__' mantığıyla eşleştirdim. –