비동기 함수 구현 (with Python, NodeJS)

MoonDD·2023년 2월 3일
0

비동기란?

가볍게 말하면 함수를 호출하고 결과값을 기다리지 않고 다음 일을 진행하는 것이다.

반면에 보통 내가 구현해왔던 동기함수는 호출하면 return을 기다리고 다음줄의 명령어를 진행하는 방식으로 진행해왔다.

그래서 파이썬으로 구현하면서 왜 비동기를 사용해야하는 지에 대해 알아보았다.

핵심문법

async def do_async(imarg)

기존 def 키워드 앞에 async를 붙이면 해당 함수는 비동기 처리가 된다. 요것을 코루틴이라고 부른다.

코루틴과 쓰레드의 차이 설명

ansyncio

import asyncio

asyncio는 비동기 관련 기능을 담고 있는 모듈이다. 이걸 임포트하면 이벤트루프에 일거리를 넣어줄 수 있는 함수들을 사용할 수 있다.

비동기 함수 호출방법

코루틴을 일반 함수처럼 냅다 호출하면 결과값을 코루틴 객체가 리턴된다.

asyncio.run()

import asyncio

async def do_async():
	return

asyncio.run(do_async())

asyncio.get_event_loop()

asyncio.get_event_loop() 을 이용해 async로 선언하지 않은 동기함수안에서 호출할 수 있다.

이벤트 루프는 비동기 작업들을 등록하면 내부적으로 루프를 돌며 등록된 작업들을 하나씩 실행하고 완료 시 그 결과를 통보해준다.

def do_sync(imarg):
	event_loop = asyncio.get_event_loop()
	event_loop.run_in_executor(None, do_async, imarg)

await

await 를 사용해 async로 선언된 비동기함수안에서 호출할 수 있다.

async def do_other_async():
	await do_async()

await키워드는 “다음으로 바로 진행하지말고, 이벤트 루프에 있는 일거리 하면서 결과값 기다려!”라는 의미를 가지고 있다. 그러면 비동기가 아니지 않나? 라고 생각이 들었지만 await는 마냥 기다리는 것이 아닌 이벤트 루프에 있는 일거리를 하면서 기다리는 것라고 한다.

asyncio.gather()
gather()을 이용해서 비동기 작업들을 이벤트 루프에 한번에 등록할 수 있다.

async def main() :
    await asyncio.gather(
        do_async(),
				do_async(),
				do_async()
    )

하여튼 위에서 배운 걸 이용해서 비동기함수를 작성해보았다.

코드 및 실행결과

동기함수

비동기함수

위 코드 캡쳐본이 잘 안보일까봐 아래에 복붙함

import time
import requests
import asyncio

async def download_page(url):
    event_loop = asyncio.get_event_loop() #이벤프 루프 가져오기
    req = await event_loop.run_in_executor(None, requests.get, url) #request.get은 동기함수이니, 지정된 executer에서 request.get이 호출되도록 지정 
    html = req.text
    print(" Success to download page : ", url, "and size of page ( ", len(html), " ) ")

async def main():
    await asyncio.gather( #이벤트 루프에 비동기 작업들 넣기
        download_page("https://www.python.org/"),
        download_page("https://www.python.org/"),
        download_page("https://www.python.org/"),
        download_page("https://www.python.org/"),
        download_page("https://www.python.org/")
    )

print(f"Start time : {time.strftime('%X')}")
start_time = time.time()
asyncio.run(main()) #비동기함수 호출
end_time = time.time()
print(f"End time : {time.strftime('%X')}, Total:{end_time-start_time} sec(s)")

node js로 구현

function setTimeoutPromise(ms){
    //ms이후에 resolove함수 호출
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(), ms);
    });
}

async function fetchAge(id){
    await setTimeoutPromise(1000); //Promise가 완료될때까지 기다리기
    console.log(`${id} 사원 데이터 받아오기 완료!`);
    return parseInt(Math.random() * 20 , 10) + 25;
}

async function startsAsyncsJobs(){
    let promises = []
    for (let i = 0; i < 10; i++){
        promises.push(fetchAge(i)); //promise를 배열에 쌓아두기
    }

    let ages = await Promise.all(promises); //배열로 받은 promise들이 성공하면 resolve를 호출, 실패하면 reject를 호출

    console.log(
        `평균 나이는 ? ==> ${
            ages.reduce((prev, current) => prev + current, 0) / ages.length
        }`
    );
}

startsAsyncsJobs();

참조

0개의 댓글