Python 프로그램에서 이벤트 루프를 기반으로 한 비동기 프로그래밍 방법을 채택하면 이 방법이 훌륭해서가 아니라 사용자가 Python 프로그램에 링크가 없는지 확인하는 방법을 찾아야 하기 때문에 무의식적으로 그것에 매력을 느끼게 될 것입니다. 프로그램이 차단되었습니다!
예를 들어 현재 시나리오는 MongoDB에서 처리되지 않은 데이터를 모두 읽고 이미지 정보를 다운로드하여 저장한 다음 데이터베이스의 내용을 업데이트하는 것입니다. Python에서 흔히 사용되는 MongoDB 비동기 드라이버는 Motor:
asyncio와 조합하여 사용하는 방법은 다음과 같습니다. 작업이 차단되므로 비동기 처리가 의미가 없습니다. 물론 비동기 네트워크 요청 라이브러리인 aiohttp를 사용하여 이미지를 다운로드할 수 있습니다.
import motor.motor_asyncio import asyncio client = motor.motor_asyncio.AsyncIOMotorClient() db = client.test_database async def run(): async for mm in db.test_database.find({"status": 0}): print(mm['img_src']) # Download Image Here # dl_img(mm['img_src']) await db.test_database.update({"_id": mm['_id']}, {"$set": {"status":1}}) loop = asyncio.get_event_loop() loop.run_until_complete(run())
물론 시스템 명령줄 도구(예: wget)를 직접 호출할 수도 있습니다. ) 직접 다운로드하지 않고 다운로드 작업을 완료합니다. Python은 하위 프로세스 표준 라이브러리를 통해 시스템 명령 호출을 구현합니다(이전 os.system(cmd) 대체). 다운로드 작업을 수행하려면 다음만 필요합니다.
async with session.get(img) as resp: with open(img.split("/")[-1], 'wb') as fd: while True: chunk = await resp.content.read(1024) if not chunk: break fd.write(chunk)
호출 메서드는 asyncio의 이벤트 루프에서 직접 사용할 수 없지만 asyncio는 해당 하위 프로세스 인터페이스를 제공합니다.
import subprocess as sb sb.run(['wget', img], shell=True)
두 메서드 모두 asyncio.subprocess.Process 인스턴스를 반환하고 해당 인터페이스 디자인은 subprocess.Popen(위에서 언급한 subprocess.run()의 기본 구현)을 완전히 모방하므로 해당 사용법이 이벤트 루프에 쉽게 이식됩니다.
asyncio.create_subprocess_exec(*args, ...) asyncio.create_subprocess_shell(cmd, ...)
위 시나리오의 사용법 외에도 명령줄 실행을 작업으로 이벤트 루프에 직접 넣을 수도 있습니다.
async def dl_img(src): dl = await asyncio.create_subprocess_shell('wget {} -O {}'.format(src, src.split("/")[-1]) await dl.wait()
요약
Python에서 비동기 프로그래밍의 의미는 CPU가 IO를 차단하도록 하는 것이 아니므로 모든 차단 작업에서 올바른 비동기 방법을 사용하도록 주의해야 합니다. 이러한 작업이 비동기 작업으로 캡슐화되면, 후속 스케줄 실행에 대해 걱정할 필요가 없습니다.loop = asyncio.get_event_loop() sb = asyncio.create_subprocess_shell('exit 7', loop=loop) proc = loop.run_until_complete(sb) exitcode = loop.run_until_complete(proc.wait())