Python coroutine 기반 networking 구현을 위한 gevent 패키지 알아보기
오늘은 Python으로 coroutine 기반의 networking을 구현할 수 있는 gevent 패키지에 대하여 알아보려 합니다.
개요
이벤트 루프에 동기 API를 제공하는 coroutine 기반 Python 네트워킹 라이브러리입니다.
몽키 패치에 의해 기존의 블로킹 코드에 맞춰서 개발해도 non-blocking I/O로 확장할 수 있습니다.
gevent 설치
우선 virtualenv로 파이썬 환경을 분리해줍니다.
pip3 install virtualenv
virtualenv -mvenv env
env라는 이름의 가상 환경을 생성합니다.
source env/bin/activate
가상환경을 폴더에서 활성화합니다.
pip install gevent
pip로 gevent를 설치합니다.
소켓
import gevent
from gevent import socket
gevent와 socket을 가져옵니다.
urls = ['www.google.com', 'www.python.org']
url들을 저장합니다.
jobs = [gevent.spawn(socket.gethostbyname, url) for url in urls]
spawn으로 Greenlet 객체를 만들고 함수를 수행합니다.
gevent.joinall(jobs, timeout=2)
greenlets이 끝날 때까지 기다립니다.
content = [job.value for job in jobs]
print(content)
얻은 값을 출력합니다.
몽키 패치
import gevent
from gevent import monkey
gevent와 몽키 패치를 위해 monkey를 가져옵니다.
monkey.patch_all()
몽키 패치는 실행중인 프로그램의 메모리 소스를 바꾸는 것으로서, non-blocking으로 바꾸어 주는 역할을 합니다.
import requests
requests 라이브러리를 가져옵니다.
pip install requests 를 수행해야 합니다.
urls = [
'https://www.google.com/',
'https://www.python.org/'
]
def print_header(url):
data = requests.get(url).text
print('%s: %r' % (url, data))
jobs = [gevent.spawn(print_header, _url) for _url in urls]
gevent.wait(jobs)
쓰레드
import time
import gevent
from gevent.threadpool import ThreadPool
gevent와 미리 쓰레드를 할당할 수 있는 ThreadPool을 가져옵니다.
pool = ThreadPool(3)
3개의 ThreadPool을 할당합니다.
for _ in range(4):
pool.spawn(time.sleep, 1)
그리고 time.sleep 함수를 할당합니다.
gevent.wait()
이벤트 루프가 끝날 때까지 기다립니다.
프로세스
import gevent
from gevent import subprocess
gevent와 새로운 프로세스를 만들고 파이프로 입출력할 수 있는 subprocess를 가져옵니다.
p1 = subprocess.Popen(['uname'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['ls'], stdout=subprocess.PIPE)
gevent.wait([p1, p2], timeout=2)
기본적인 프로세스 생성을 Popen에서 담당하고, wait로 이벤트 루프가 끝날 때까지 기다립니다.
if p1.poll() is not None:
print('%r' % p1.stdout.read())
if p2.poll() is not None:
print('%r' % p2.stdout.read())
poll로 프로세스가 종료되었는지 확인하면서 None이 아니라면 값을 출력합니다.
p1.stdout.close()
p2.stdout.close()
stdout를 닫습니다.