프로그래밍 세계에서는 "비차단"이라는 개념이 널리 퍼져 있습니다. JavaScript 개발자는 JavaScript의 장점 중 하나인 "비동기"라는 용어를 자주 사용합니다. 그러나 비동기 프로그래밍을 진정으로 이해하려면 동시 프로그래밍과 병렬 프로그래밍의 개념을 이해하는 것이 중요합니다.
여러 독립 엔터티가 동시에 작업할 때 프로그래밍은 동시입니다. 이는 이러한 작업이 정확히 동시에 실행된다는 의미는 아닙니다. 대신, 이는 CPU 시간과 같은 리소스를 공유하여 시간이 지남에 따라 작업이 진행되고 있음을 의미합니다. 동시 프로그래밍의 가장 큰 장점은 견고성입니다. 하나의 프로세스가 충돌하더라도 나머지 프로그램은 계속 작동합니다.
알고리즘이 작업을 여러 부분으로 나눌 수 있으면 병렬입니다. 프로세서가 많을수록 병렬 처리의 이점이 커집니다. 효율적인 병렬 프로그래밍은 더 나은 성능을 위해 최신 기계의 리소스를 최적화합니다.
동시성 예:
고기를 굽고 소스를 만들어야 하는 식사를 준비하고 있다고 상상해 보세요. 바베큐에 고기를 올려놓는 것부터 시작합니다. 고기가 굽는 동안 소스에 들어갈 토마토와 다른 야채를 잘게 썰어주세요. 그런 다음 가끔씩 고기의 상태를 확인하면서 소스를 끓이기 시작합니다. 여기서는 두 가지 작업(고기 굽기와 소스 만들기)이 모두 진행 중이지만, 주의가 그 사이로 전환되고 있습니다. 이는 동시성을 나타냅니다.
병렬성 예:
이제 당신을 도와줄 친구가 있다고 가정해 보겠습니다. 당신이 고기 굽는 데 집중하는 동안 친구는 소스 만드는 일을 맡아요. 두 작업은 서로 주의를 전환할 필요 없이 동시에 수행됩니다. 이는 병렬성을 나타냅니다.
비동기 프로그래밍에는 사용자 입력, 터미널에 인쇄, 소켓에서 읽기, 디스크에 쓰기 등 프로그램 외부에서 발생하는 입출력(I/O) 작업을 처리하는 작업이 포함됩니다. 비동기 I/O의 주요 특징은 다음과 같습니다.
작업에 소요되는 시간은 CPU에 따라 달라지지 않습니다. 대신 디스크 속도, 네트워크 지연 시간, 기타 외부 조건과 같은 요인에 따라 달라집니다.
프로그램은 작업이 언제 종료될지 예측할 수 없습니다.
I/O가 많은 서비스(예: 웹 서버, 데이터베이스, 배포 스크립트)의 경우 이러한 작업을 최적화하면 성능이 크게 향상될 수 있습니다.
차단 코드와 비차단 코드의 예를 살펴보겠습니다.
간단한 프로그램을 고려해보세요:
import time def task(): time.sleep(2) print("Hello") for _ in range(3): task()
이 동기 프로그램에서 각 작업은 이전 작업이 완료될 때까지 기다리므로 지연이 발생합니다.
이제 asyncio를 사용한 비동기 버전을 살펴보겠습니다.
import asyncio async def task(): await asyncio.sleep(2) print("Hello") async def main(): tasks = [task() for _ in range(3)] await asyncio.gather(*tasks) asyncio.run(main())
이 비동기 프로그램에서는 작업이 동시에 실행되어 총 실행 시간이 단축됩니다. 비동기 프로그래밍의 구성요소를 살펴보겠습니다.
이벤트 루프, 코루틴 및 미래는 비동기 Python 프로그램의 필수 요소입니다.
이벤트 루프: 작업 전환 및 실행 흐름을 관리하여 비동기적으로 실행될 작업을 추적합니다.
코루틴: 일시 중지하고 다시 시작할 수 있는 특수 기능으로 대기 중에 다른 작업을 실행할 수 있습니다. 코루틴은 함수에서 작업 전환 이벤트가 발생해야 하는 위치를 지정하고 이벤트 루프에 제어권을 반환합니다. 코루틴은 일반적으로 이벤트 루프에 의해 생성되며 내부적으로 작업 대기열에 저장됩니다.
Futures: 코루틴 결과에 대한 자리 표시자로서 결과 또는 예외를 저장합니다. 이벤트 루프가 코루틴을 시작하자마자 코루틴의 결과를 저장하는 해당 future가 생성되거나 코루틴 실행 중에 예외가 발생한 경우 예외가 생성됩니다.
파이썬 비동기 프로그래밍의 중요한 부분을 설명하고 몇 가지 코드를 작성해 보겠습니다.
이제 비동기 프로그래밍 패턴을 이해했으므로 간단한 스크립트를 작성하고 실행을 분석해 보겠습니다. 다음은 간단한 비동기 스크립트입니다:
import asyncio async def task(): await asyncio.sleep(2) print("Hello") async def main(): tasks = [task() for _ in range(3)] await asyncio.gather(*tasks) asyncio.run(main())
위 코드에서는 실행 중인 다른 작업이 절전 모드(차단) 상태인 경우에도 다른 작업의 실행을 계속하려고 합니다. 작업 및 기본 기능 앞에 있는 async 키워드를 확인하세요.
이러한 함수는 이제 코루틴입니다.
Python의 코루틴 함수 앞에는 async 키워드가 옵니다. 여기서 main() 함수는 async.gather 메서드를 사용하여 모든 작업을 실행하므로 작업 코디네이터 또는 단일 이벤트 루프입니다. asyncio.gather 함수는 대기 가능한 객체를 동시에 실행합니다.
산출:
Hello Hello Hello Program executed in 2.01 seconds.
각 작업이 wait asyncio.sleep(2)에 도달하면 다음 작업으로 이동했다가 완료되면 다시 돌아옵니다. 2초만 자고 딴 짓 하라고 하는 것과 같다.
빠른 비교를 위해 동기 버전을 살펴보겠습니다.
import time def task(): time.sleep(2) print("Hello") for _ in range(3): task()
위의 코드에서는 Python의 전통적인 프로그래밍 방식을 사용하고 있습니다. 프로세스 실행에 훨씬 더 많은 시간이 소요된다는 것을 알 수 있습니다.
산출:
Hello Hello Hello Program executed in 6.01 seconds.
이제 실행 시간을 확인할 수 있습니다. time.sleep()을 차단 작업으로 생각하고 asyncio.sleep()을 비차단 또는 긴 작업으로 생각하세요. 비동기 프로그래밍에서 asyncio.sleep()과 같은 것을 기다리는 것의 이점은 주변 함수가 즉시 실행할 준비가 된 다른 함수에 일시적으로 제어권을 넘겨줄 수 있다는 것입니다.
Python의 비동기 프로그래밍에 대한 몇 가지 기본 예를 이해하고 Python의 비동기 프로그래밍 규칙을 살펴보겠습니다.
코루틴: 코루틴은 직접 실행할 수 없습니다. 코루틴 함수를 직접 실행하려고 하면 코루틴 객체가 반환됩니다. 대신 asyncio.run():
를 사용하세요.
import asyncio async def hello(): await asyncio.sleep(1) print('Hello') asyncio.run(hello())
대기 가능한 객체: 코루틴, 퓨처 및 작업은 대기 가능한 주요 객체입니다. Python 코루틴은 어웨이터블이며 다른 코루틴에서 어웨이트될 수 있습니다.
Await 키워드:await는 비동기 함수 내에서만 사용할 수 있습니다.
async def hello(): await asyncio.sleep(1) print("Hello")
호환성: 모든 Python 모듈이 비동기 프로그래밍과 호환되는 것은 아닙니다. 예를 들어, wait asyncio.sleep()을 time.sleep()으로 바꾸면 오류가 발생합니다. 여기에서 호환 가능하고 유지 관리되는 모듈 목록을 확인할 수 있습니다.
다음 섹션에서는 비동기 프로그래밍, HTTP 요청의 일반적인 사용을 살펴보겠습니다.
다음 코드를 살펴보겠습니다.
import aiohttp import asyncio async def fetch(session, city): url = f"https://www.prevision-meteo.ch/services/json/{city}" async with session.get(url) as response: data = await response.json() print(f"Temperature at {city}: {data['current_condition']['tmp']} C") async def main(): async with aiohttp.ClientSession() as session: cities = ['paris', 'toulouse', 'marseille'] tasks = [fetch(session, city) for city in cities] await asyncio.gather(*tasks) asyncio.run(main())
위 코드에서는 두 개의 비동기 함수를 생성합니다. 하나는 prevision-meteo URL에서 데이터를 가져오는 함수이고 다른 하나는 Python 코드에서 프로세스를 실행하는 기본 함수입니다. 목표는 비동기 HTTP GET 요청을 보내 온도를 검색하고 응답을 인쇄하는 것입니다.
메인 및 가져오기 기능에서는 async with를 사용합니다. 가져오기 기능에서 async with는 연결이 제대로 닫히도록 보장합니다. 기본 기능에서는 요청 완료 후 ClientSession이 닫히도록 합니다. 이러한 방법은 Python의 비동기 코딩에서 리소스를 효율적으로 관리하고 누출을 방지하는 데 중요합니다.
메인 함수의 마지막 줄에서는 wait asyncio.gather(*tasks)를 사용합니다. 우리의 경우 모든 작업을 동시에 실행하여 프로그램이 여러 HTTP 요청을 동시에 보낼 수 있도록 합니다. Wait를 사용하면 프로그램이 진행하기 전에 모든 작업이 완료될 때까지 기다립니다.
산출:
Temperature at marseille: 25 C Temperature at toulouse: 24 C Temperature at paris: 18 C Program executed in 5.86 seconds.
암호:
import requests import time def fetch(city): url = f"https://www.prevision-meteo.ch/services/json/{city}" response = requests.get(url) data = response.json() print(f"Temperature at {city}: {data['current_condition']['tmp']} C") def main(): cities = ['paris', 'toulouse', 'marseille'] for city in cities: fetch(city) start_time = time.time() main() print(f"Program executed in {time.time() - start_time:.2f} seconds.")
산출:
Temperature at Paris: 18 C Temperature at Toulouse: 24 C Temperature at Marseille: 25 C Program executed in 9.01 seconds.
비동기 모델은 다음과 같은 경우에 가장 잘 작동합니다.
작업 수가 많기 때문에 항상 하나 이상의 작업을 진행할 수 있습니다.
작업에는 상당한 I/O가 포함되어 있어 비동기 프로그램이 다른 작업이 실행될 수 있는 시간을 차단하는 데 많은 시간을 낭비하게 됩니다.
작업은 대체로 독립적이어서 작업 간 통신을 최소화합니다(따라서 한 작업이 다른 작업을 기다리게 됨).
이 튜토리얼에서는 다음 내용을 다루었습니다.
비동기 프로그래밍의 개념과 관련 개념.
async/await를 효과적으로 사용합니다.
aiohttp를 사용하여 비동기 HTTP 요청 만들기
비동기 프로그래밍의 이점.
읽어주셔서 감사합니다. 두 번째 부분에서는 Django를 사용한 비동기 프로그래밍을 다룹니다.
Python 문서: 코루틴 및 작업
Python 문서: asyncio - 비동기 I/O
aiohttp 문서
Aio 라이브러리
동시성과 병렬성
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3