>  기사  >  백엔드 개발  >  Asyncio를 사용한 비동기 프로그래밍

Asyncio를 사용한 비동기 프로그래밍

PHPz
PHPz원래의
2024-07-23 16:59:24702검색

Asynchronous Programming with Asyncio

프로그래밍 세계에서는 "논 블로킹"이라는 개념이 널리 퍼져 있습니다. 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 프로그램의 필수 요소입니다.

  • 이벤트 루프: 작업 전환 및 실행 흐름을 관리하고 비동기적으로 실행될 작업을 추적합니다.

  • 코루틴: 일시 중지 및 재개가 가능한 특수 기능으로 대기 중에 다른 작업을 실행할 수 있습니다. 코루틴은 함수에서 작업 전환 이벤트가 발생해야 하는 위치를 지정하고 이벤트 루프에 제어권을 반환합니다. 코루틴은 일반적으로 이벤트 루프에 의해 생성되며 내부적으로 작업 대기열에 저장됩니다.

  • 퓨처: 코루틴 결과에 대한 자리 표시자, 결과 또는 예외 저장. 이벤트 루프가 코루틴을 시작하자마자 코루틴 결과를 저장하는 해당 future가 생성되거나, 코루틴 실행 중에 예외가 발생한 경우 예외가 생성됩니다.

Python 비동기 프로그래밍의 중요한 부분을 설명하고 코드를 작성해 보겠습니다.

비동기 코드 작성

이제 비동기 프로그래밍 패턴을 이해했으므로 간단한 스크립트를 작성하고 실행을 분석해 보겠습니다. 다음은 간단한 비동기 스크립트입니다.

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 키워드가 있는지 확인하세요.

이러한 기능은 이제 코루틴입니다.

Coroutines functions in Python are preceded by the keyword async. The main() function here is the task coordinator or our single event loop, as it executes all tasks using the async.gather method. The asyncio.gather function runs awaitable objects concurrently.

Output:

Hello
Hello
Hello
Program executed in 2.01 seconds.

When each task reaches await asyncio.sleep(2), it simply goes to the next task and comes back when it's finished. It's like saying, "I am going to sleep for 2 seconds. Do something else."

Let's see the synchronous version for a quick comparison.

import time

def task():
    time.sleep(2)
    print("Hello")

for _ in range(3):
    task()

In the code above, we are going the traditional programming way in Python. You will notice that the execution of the process will take much more time.

Output:

Hello
Hello
Hello
Program executed in 6.01 seconds.

Now you can notice the execution time. Think of time.sleep() as a blocking task and asyncio.sleep() as a non-blocking or long task. In asynchronous programming, the benefit of awaiting something, like asyncio.sleep(), is that the surrounding function can temporarily cede control to another function that is ready to execute immediately.

With some basic examples of asynchronous programming in Python understood, let's explore the rules of asynchronous programming in Python.

Rules of Asyncio Programming

  1. Coroutines: Coroutines cannot be executed directly. If you try to run a coroutine function directly, it returns a coroutine object. Instead, use asyncio.run():

    import asyncio
    
    async def hello():
        await asyncio.sleep(1)
        print('Hello')
    
    asyncio.run(hello())
    
  2. Awaitable Objects: Coroutines, futures, and tasks are the main awaitable objects. Python coroutines are awaitables and can be awaited from other coroutines.

  3. Await Keyword:await can only be used within async functions.

    async def hello():
        await asyncio.sleep(1)
        print("Hello")
    
  4. Compatibility: Not all Python modules are compatible with asynchronous programming. For example, replacing await asyncio.sleep() with time.sleep() will cause an error. You can check the list of compatible and maintained modules here.

In the next section, we will explore a common use of asynchronous programming, HTTP requests.

Program Example: Asynchronous Requests

Let's take a look at the following piece of code:

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())

In the code above, we create two asynchronous functions: one to fetch data from the prevision-meteo URL and a main function to execute the processes in the Python code. The goal is to send asynchronous HTTP GET requests to retrieve temperatures and print the responses.

In the main and fetch functions, we use async with. In the fetch function, async with ensures that the connection is closed properly. In the main function, it ensures that the ClientSession is closed after completing the requests. These practices are important in asynchronous coding in Python to manage resources efficiently and prevent leaks.

In the last line of the main function, we use await asyncio.gather(*tasks). In our case, it runs all tasks concurrently, allowing the program to send multiple HTTP requests simultaneously. Using await ensures that the program waits for all tasks to complete before proceeding.

Output:

Temperature at marseille: 25 C
Temperature at toulouse: 24 C
Temperature at paris: 18 C
Program executed in 5.86 seconds.

Synchronous Version for Comparison

Code:

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.")

Output:

Temperature at Paris: 18 C
Temperature at Toulouse: 24 C
Temperature at Marseille: 25 C
Program executed in 9.01 seconds.

When to Use Asynchronous Programming

The asynchronous model performs best when:

  • There are a large number of tasks, ensuring at least one task can always progress.

  • Tasks involve significant I/O, causing an asynchronous program to waste lots of time blocking when other tasks could be running.

  • Tasks are largely independent, minimizing inter-task communication (and thus for one task to wait upon another).

Conclusion

In this tutorial, we covered:

  • The concepts of asynchronous programming and related concepts.

  • Effective use of async/await.

  • Making asynchronous HTTP requests with aiohttp.

  • The benefits of asynchronous programming.

Thanks for reading. The second part will cover asynchronous programming with Django.

Resources

  • Python Documentation: Coroutines and Tasks

  • Python Documentation: asyncio - Asynchronous I/O

  • aiohttp Documentation

  • Aio Libraries

  • Concurrency vs Parallelism

위 내용은 Asyncio를 사용한 비동기 프로그래밍의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:CPU 시뮬레이터다음 기사:CPU 시뮬레이터