2016-09-30 3 views
4

저는 파이썬에서 (그리고 일반적으로) 코 루틴을 이해하려고합니다. 이론, 개념 및 몇 가지 예를 읽었지만 여전히 고민 중입니다. 나는 비동기식 모델을 이해하지만 코 루틴은 아직 이해하지 못했다.이것은 어떻게 코 루틴인가?

async def download_coroutine(url, number): 
    """ 
    A coroutine to download the specified url 
    """ 
    request = urllib.request.urlopen(url) 
    filename = os.path.basename(url) 
    print("Downloading %s" % url) 

    with open(filename, 'wb') as file_handle: 
     while True: 
      print(number) # prints numbers to view progress 
      chunk = request.read(1024) 
      if not chunk: 
       print("Finished") 
       break 
      file_handle.write(chunk) 
    msg = 'Finished downloading {filename}'.format(filename=filename) 
    return msg 

이이

coroutines = [download_coroutine(url, number) for number, url in enumerate(urls)] 
completed, pending = await asyncio.wait(coroutines) 

이 발전기를 찾고 실행이 내가 할 수있는 예를 코 루틴 :

tutorial이는 코 루틴 예제로 (나는 내 ​​문제를 설명하기 위해 몇 가지 변경을) 제공 몇 가지 yield 문을 참조하십시오. 여기에는 아무것도 없으며 urllib은 동기식입니다. AFAIK.

또한 코드는 비동기식이기 때문에 일련의 인터리브 된 숫자가 표시 될 것으로 예상됩니다. (1, 4, 5, 1, 2, ..., "Finished", ...). 내가보고있는 것은 하나의 숫자가 Finished으로 끝나고 다른 하나 (3, 3, 3, 3, ... "Finished", 1, 1, 1, 1, ..., "Finished"로 끝나는 것입니다. ..).

이 시점에서 저는 튜토리얼이 잘못되었다고 말하고 싶습니다. 이것은 비동기가 앞에 있기 때문에 코 루틴입니다.

+2

당신은'async def'를 사용했기 때문에 그냥 일종의 루틴 *입니다. 다른 협동 작업에 결코 굴하지 않는 것은 매우 협력적인 것이 아닙니다. 네, 당신의 분석은 정확합니다. –

+0

제가 처음에 그 튜토리얼을 쓴 것은 실수였습니다. 'aiohttp'를 사용하도록 업데이트되었습니다. –

답변

12

협력을 의미코 루틴에 공동. 항복 (다른 루틴으로)은 루틴을 공동 루틴으로 만듭니다. 실제로 기다릴 때 항복 만하면 다른 루틴을 인터리브 할 수 있기 때문입니다. 새로운 async 파이썬 3.5 이상의 세계에서 이것은 보통 다른 코 루틴의 결과 인 await에 의해 달성됩니다.

그 정의에 따르면, 코드는 이 아니며 코 루틴은입니다. 마찬가지로 까지 파이썬이 염려됩니다. 오브젝트입니다. 이는 async def을 사용하여 작성된 함수 오브젝트에 지정된 유형이기 때문입니다.

그래,이 튜토리얼은 코 루틴 (coroutine) 함수 내에서 완전히 동기적이고 비협조적인 코드를 사용한다는 점에서 도움이되지 않습니다.

urllib 대신 비동기 HTTP 라이브러리가 필요합니다. aiohttp처럼 : 다시 세션을 닫을 때뿐만 아니라, 더 많은 네트워크 데이터를 기다릴 때 연결이 설정 될 때까지 기다리고, 언제

import aiohttp 

async def download_coroutine(url): 
    """ 
    A coroutine to download the specified url 
    """ 
    filename = os.path.basename(url) 
    async with aiohttp.ClientSession() as session: 
     async with session.get(url) as resp: 
      with open(filename, 'wb') as fd: 
       while True: 
        chunk = await resp.content.read(1024) 
        if not chunk: 
         break 
        fd.write(chunk) 
    msg = 'Finished downloading {filename}'.format(filename=filename) 
    return msg 

이 코 루틴은 다른 루틴을 얻을 수 있습니다.

파일을 비동기 적으로 작성할 수 있지만 그 파일은 has portability issues입니다. aiofiles project 라이브러리는 스레드를 사용하여 차단 호출을 오프로드합니다.

import aiofiles 

async with aiofiles.open(filename, 'wb') as fd: 
    while True: 
     chunk = await resp.content.read(1024) 
     if not chunk: 
      break 
     await fd.write(chunk) 

: 해당 라이브러리를 사용하여 코드를 업데이트 할 필요가 블로그 게시물 이후 이러한 문제를 해결하기 위해 업데이트되었습니다.

+0

저는 오랫동안 python2.7 프로그래머였습니다. 어떤 이유로 새로운 파이썬을 피했습니다. 나는 원래 튜토리얼과이 SO 엔트리가 매우 유용하다는 것을 알았다. 나는이 질문/답변에 더 많은 상향 신호가 없다는 것을 당황스럽게 생각합니다. 주제 분야가 전문입니까? 잘 하셨어요! – Greg

+0

@Greg : coroutines는 Python에 비교적 새로 추가 된 기능이므로 많은 사람들이 아직 Python을 사용하지 않았습니다. –