KR_AsyncIO - somaz94/python-study GitHub Wiki
AsyncIO๋ ํ์ด์ฌ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
import asyncio
async def hello():
print('Hello')
await asyncio.sleep(1)
print('World')
# ์คํ
asyncio.run(hello())
โ
ํน์ง:
- ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ์ง์
- ์ฝ๋ฃจํด ๊ธฐ๋ฐ ๋์
- ๋จ์ผ ์ค๋ ๋์์ ๋์์ฑ ๊ตฌํ
์ฝ๋ฃจํด์ ์ผ์ ์ค๋จ๋๊ณ ๋์ค์ ์ฌ๊ฐ๋ ์ ์๋ ๋น๋๊ธฐ ํจ์์ด๋ฉฐ, ํ์คํฌ๋ ์ฝ๋ฃจํด์ ์คํํ๋ ๋จ์์ด๋ค.
async def task1():
print('Task 1 ์์')
await asyncio.sleep(2)
print('Task 1 ์ข
๋ฃ')
return 'Task 1 ๊ฒฐ๊ณผ'
async def task2():
print('Task 2 ์์')
await asyncio.sleep(1)
print('Task 2 ์ข
๋ฃ')
return 'Task 2 ๊ฒฐ๊ณผ'
async def main():
# ๋์์ ์ฌ๋ฌ ํ์คํฌ ์คํ
results = await asyncio.gather(
task1(),
task2()
)
print(f'๊ฒฐ๊ณผ: {results}')
asyncio.run(main())
โ
ํน์ง:
- ์ฌ๋ฌ ํ์คํฌ ๋์ ์คํ
- ๊ฒฐ๊ณผ ์์ง ๊ฐ๋ฅ
- ๋น๋๊ธฐ ์์ ์กฐ์จ
์ด๋ฒคํธ ๋ฃจํ๋ AsyncIO์ ํต์ฌ ์คํ ์ฅ์น๋ก, ๋น๋๊ธฐ ํ์คํฌ๋ฅผ ๊ด๋ฆฌํ๊ณ ์คํํ๋ค.
async def long_operation():
print('์์')
await asyncio.sleep(3)
print('์ข
๋ฃ')
return '์๋ฃ'
async def main():
# ์ด๋ฒคํธ ๋ฃจํ ๊ฐ์ ธ์ค๊ธฐ
loop = asyncio.get_running_loop()
# ํ์คํฌ ์์ฑ
task = loop.create_task(long_operation())
# ๋ค๋ฅธ ์์
์ํ
print('๋ค๋ฅธ ์์
์ํ ์ค...')
# ํ์คํฌ ์๋ฃ ๋๊ธฐ
result = await task
print(f'๊ฒฐ๊ณผ: {result}')
# ์คํ
asyncio.run(main())
โ
ํน์ง:
- ์ด๋ฒคํธ ๋ฃจํ ์ง์ ์ ์ด
- ํ์คํฌ ์์ฑ ๋ฐ ๊ด๋ฆฌ
- ๋น๋๊ธฐ ์์ ์ค์ผ์ค๋ง
๋น๋๊ธฐ ์ปจํ
์คํธ ๋งค๋์ ๋ ๋น๋๊ธฐ ๋ฆฌ์์ค๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
class AsyncResource:
async def __aenter__(self):
print('๋ฆฌ์์ค ํ๋')
await asyncio.sleep(1)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print('๋ฆฌ์์ค ํด์ ')
await asyncio.sleep(1)
async def use_resource():
async with AsyncResource() as resource:
print('๋ฆฌ์์ค ์ฌ์ฉ ์ค')
await asyncio.sleep(1)
# ์คํ
asyncio.run(use_resource())
โ
ํน์ง:
- ๋น๋๊ธฐ ๋ฆฌ์์ค ๊ด๋ฆฌ
- ์๋ ์ ๋ฆฌ ๋ณด์ฅ
- ์ปจํ ์คํธ ๊ธฐ๋ฐ ์์
๋น๋๊ธฐ ๋ฐ๋ณต์๋ ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ํํ ์ ์๊ฒ ํด์ค๋ค.
class AsyncCounter:
def __init__(self, limit):
self.limit = limit
self.counter = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.counter < self.limit:
self.counter += 1
await asyncio.sleep(0.1)
return self.counter
raise StopAsyncIteration
async def use_counter():
async for i in AsyncCounter(5):
print(f'์นด์ดํธ: {i}')
# ์คํ
asyncio.run(use_counter())
โ
ํน์ง:
- ๋น๋๊ธฐ ๋ฐ๋ณต ์ง์
- ์ง์ฐ ์คํ ๊ฐ๋ฅ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ฒ๋ฆฌ
์ค์ ์ ํ๋ฆฌ์ผ์ด์
์์ AsyncIO๋ฅผ ํ์ฉํ๋ ๋ค์ํ ์์ ๋ฅผ ์ดํด๋ณด์.
import aiohttp
import asyncio
async def fetch_url(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
'http://example.com',
'http://example.org',
'http://example.net'
]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for url, html in zip(urls, results):
print(f'{url}: {len(html)} bytes')
asyncio.run(main())
import asyncpg
async def create_table(pool):
async with pool.acquire() as conn:
await conn.execute('''
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT,
email TEXT
)
''')
async def insert_user(pool, name, email):
async with pool.acquire() as conn:
return await conn.fetchval(
'INSERT INTO users(name, email) VALUES($1, $2) RETURNING id',
name, email
)
async def main():
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ํ ์์ฑ
pool = await asyncpg.create_pool(
user='user',
password='password',
database='dbname',
host='localhost'
)
await create_table(pool)
# ๋น๋๊ธฐ๋ก ์ฌ๋ฌ ์ฌ์ฉ์ ์ถ๊ฐ
users = [
('User1', '[email protected]'),
('User2', '[email protected]'),
('User3', '[email protected]')
]
tasks = [insert_user(pool, name, email) for name, email in users]
user_ids = await asyncio.gather(*tasks)
print(f'์ถ๊ฐ๋ ์ฌ์ฉ์ ID: {user_ids}')
await pool.close()
import aiofiles
import asyncio
async def read_large_file(filename):
async with aiofiles.open(filename, mode='r') as f:
contents = await f.read()
return contents
async def write_file(filename, data):
async with aiofiles.open(filename, mode='w') as f:
await f.write(data)
async def process_files():
# ๋์์ ์ฌ๋ฌ ํ์ผ ์ฝ๊ธฐ
files = ['file1.txt', 'file2.txt', 'file3.txt']
tasks = [read_large_file(file) for file in files]
contents = await asyncio.gather(*tasks)
# ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ ์ ์ฅ
processed = [f"Processed: {content[:100]}..." for content in contents]
# ๋์์ ์ฌ๋ฌ ํ์ผ ์ฐ๊ธฐ
write_tasks = [
write_file(f"processed_{file}", data)
for file, data in zip(files, processed)
]
await asyncio.gather(*write_tasks)
print("๋ชจ๋ ํ์ผ ์ฒ๋ฆฌ ์๋ฃ")
# ์คํ
asyncio.run(process_files())
import asyncio
import random
async def producer(queue, id):
for i in range(5):
# ์์
์์ฑ
item = f"์์ฐ์ {id} - ํญ๋ชฉ {i}"
# ํ์ ํญ๋ชฉ ์ถ๊ฐ
await queue.put(item)
print(f"์์ฐ๋จ: {item}")
# ๋๋ค ์ง์ฐ
await asyncio.sleep(random.uniform(0.1, 0.5))
async def consumer(queue, id):
while True:
# ํ์์ ํญ๋ชฉ ๊ฐ์ ธ์ค๊ธฐ
item = await queue.get()
# ํญ๋ชฉ ์ฒ๋ฆฌ
print(f"์๋น์ {id} ์ฒ๋ฆฌ ์ค: {item}")
await asyncio.sleep(random.uniform(0.2, 0.6))
# ์์
์๋ฃ ํ์
queue.task_done()
async def main():
# ํ ์์ฑ
queue = asyncio.Queue()
# ์์ฐ์ ๋ฐ ์๋น์ ํ์คํฌ ์์ฑ
producers = [producer(queue, i) for i in range(3)]
consumers = [asyncio.create_task(consumer(queue, i)) for i in range(2)]
# ์์ฐ์ ์คํ ๋ฐ ๋๊ธฐ
await asyncio.gather(*producers)
# ๋ชจ๋ ํญ๋ชฉ์ด ์ฒ๋ฆฌ๋ ๋๊น์ง ๋๊ธฐ
await queue.join()
# ์๋น์ ํ์คํฌ ์ทจ์
for c in consumers:
c.cancel()
# ์คํ
asyncio.run(main())
โ
์ฃผ์ ํ:
- I/O ๋ฐ์ด๋ ์์ ์ ์ ํฉ
- ๋๊ธฐ ์ฝ๋์ ํผํฉ ์ ์ฃผ์
- ์ด๋ฒคํธ ๋ฃจํ ๋ธ๋กํน ํผํ๊ธฐ
- ์ ์ ํ ์๋ฌ ์ฒ๋ฆฌ ๊ตฌํ
- ๋น๋๊ธฐ ์ปจํ ์คํธ ๋งค๋์ ํ์ฉ
- ํ์คํฌ ์ทจ์ ์ฒ๋ฆฌ ๊ตฌํ
- ๋๋ฒ๊น ๋๊ตฌ ํ์ฉ
- ํจ์จ์ ์ธ ํ์คํฌ ๊ทธ๋ฃนํ
- ์ฝ๋ฃจํด ์ฒด์ธ ๊ตฌ์ฑ ์ ์์ธ ์ ํ ๊ณ ๋ ค
- ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์คํฌ ๊ด๋ฆฌ
AsyncIO๋ ๋ค์ํ ๋์์ฑ ์ ์ด ๋๊ตฌ๋ฅผ ์ ๊ณตํ์ฌ ๋ณต์กํ ๋น๋๊ธฐ ์์
์ ๊ด๋ฆฌํ๋ค.
import asyncio
async def worker(semaphore, id):
async with semaphore:
# ์ธ๋งํฌ์ด๋ก ์ ํ๋ ๊ตฌ์ญ
print(f"์์
์ {id} ์์")
await asyncio.sleep(1)
print(f"์์
์ {id} ์ข
๋ฃ")
async def main():
# ์ต๋ 3๊ฐ์ ๋์ ํ์คํฌ๋ง ํ์ฉ
semaphore = asyncio.Semaphore(3)
# 10๊ฐ์ ์์
๋์ ์คํ (์ต๋ 3๊ฐ์ฉ ์ฒ๋ฆฌ)
tasks = [worker(semaphore, i) for i in range(10)]
await asyncio.gather(*tasks)
# ์คํ
asyncio.run(main())
import asyncio
async def protected_resource(lock, id):
# ๋ฝ ํ๋
async with lock:
print(f"๋ฆฌ์์ค ์ฌ์ฉ ์ค (์์
์ {id})")
await asyncio.sleep(1)
print(f"๋ฆฌ์์ค ์ฌ์ฉ ์๋ฃ (์์
์ {id})")
async def main():
# ๋ฝ ์์ฑ
lock = asyncio.Lock()
# ์ฌ๋ฌ ํ์คํฌ๊ฐ ๋์ผํ ๋ฝ์ ๊ณต์
tasks = [protected_resource(lock, i) for i in range(5)]
await asyncio.gather(*tasks)
# ์คํ
asyncio.run(main())
import asyncio
async def waiter(event, id):
print(f"๋๊ธฐ์ {id}: ์ด๋ฒคํธ ๋๊ธฐ ์ค")
await event.wait()
print(f"๋๊ธฐ์ {id}: ์ด๋ฒคํธ ๋ฐ์! ์์
์งํ")
async def setter(event):
print("์ค๋น ์ค...")
await asyncio.sleep(2)
print("์ด๋ฒคํธ ์ค์ !")
# ๋ชจ๋ ๋๊ธฐ ์ค์ธ ํ์คํฌ์ ์ ํธ ๋ณด๋ด๊ธฐ
event.set()
async def main():
# ์ด๋ฒคํธ ์์ฑ
event = asyncio.Event()
# ๋๊ธฐ ํ์คํฌ์ ์ค์ ํ์คํฌ ์์ฑ
waiters = [asyncio.create_task(waiter(event, i)) for i in range(5)]
setter_task = asyncio.create_task(setter(event))
# ๋ชจ๋ ํ์คํฌ ์๋ฃ ๋๊ธฐ
await asyncio.gather(setter_task, *waiters)
# ์คํ
asyncio.run(main())
import asyncio
import random
async def consumer(condition, id, buffer):
while True:
# ์กฐ๊ฑด ํ๋ ๋ฐ ๋๊ธฐ
async with condition:
# ๋ฒํผ๊ฐ ๋น์ด์์ผ๋ฉด ๋๊ธฐ
while len(buffer) == 0:
print(f"์๋น์ {id}: ๋ฒํผ๊ฐ ๋น์ด์์ด ๋๊ธฐ ์ค")
await condition.wait()
# ํญ๋ชฉ ์๋น
item = buffer.pop(0)
print(f"์๋น์ {id}: {item} ์ฒ๋ฆฌ")
# ์์ฐ์์๊ฒ ์ ํธ
condition.notify()
await asyncio.sleep(random.uniform(0.1, 0.3))
async def producer(condition, id, buffer, max_size):
for i in range(5):
item = f"ํญ๋ชฉ {i} (์์ฐ์ {id})"
# ์กฐ๊ฑด ํ๋
async with condition:
# ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐผ์ผ๋ฉด ๋๊ธฐ
while len(buffer) >= max_size:
print(f"์์ฐ์ {id}: ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐจ์ ๋๊ธฐ ์ค")
await condition.wait()
# ํญ๋ชฉ ์์ฐ
buffer.append(item)
print(f"์์ฐ์ {id}: {item} ์์ฑ")
# ์๋น์์๊ฒ ์ ํธ
condition.notify()
await asyncio.sleep(random.uniform(0.1, 0.5))
async def main():
# ๊ณต์ ๋ฒํผ์ ์กฐ๊ฑด ๋ณ์
buffer = []
max_size = 2
condition = asyncio.Condition()
# ์์ฐ์ ๋ฐ ์๋น์ ํ์คํฌ
producers = [producer(condition, i, buffer, max_size) for i in range(2)]
consumers = [asyncio.create_task(consumer(condition, i, buffer)) for i in range(2)]
# ์์ฐ์ ์๋ฃ ๋๊ธฐ
await asyncio.gather(*producers)
# ์๋น์ ํ์คํฌ ์ทจ์
for c in consumers:
c.cancel()
# ์ทจ์๋ ํ์คํฌ ์์ธ ์ฒ๋ฆฌ
await asyncio.gather(*consumers, return_exceptions=True)
# ์คํ
asyncio.run(main())
โ
ํน์ง:
- ๋ฉํฐํ์คํน ์กฐ์
- ๋ฆฌ์์ค ๊ฒฝ์ ๊ด๋ฆฌ
- ํ์คํฌ ๊ฐ ๋๊ธฐํ
- ๋น๋๊ธฐ ์์ ํ๋ฆ ์ ์ด
- ํจ์จ์ ์ธ ๋ณ๋ ฌ ์ฒ๋ฆฌ
๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋น๋๊ธฐ ์คํธ๋ฆผ ๊ธฐ๋ฒ์ด๋ค.
import asyncio
async def number_generator(limit):
# ์คํธ๋ฆผ ์์ค
for i in range(limit):
await asyncio.sleep(0.1) # ๋ฐ์ดํฐ ์์ฑ ์๊ฐ ํ๋ด
yield i
async def process_numbers():
# ๋น๋๊ธฐ ์์ฑ๊ธฐ์์ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ
async for number in number_generator(10):
result = number * number
print(f"์ฒ๋ฆฌ: {number} -> {result}")
# ์คํ
asyncio.run(process_numbers())
import asyncio
async def data_source():
# ๋ฐ์ดํฐ ์์ค (API, ํ์ผ ๋ฑ)
for i in range(10):
await asyncio.sleep(0.2)
yield i
async def filter_even(stream):
# ์ง์๋ง ํํฐ๋ง
async for item in stream:
if item % 2 == 0:
yield item
async def multiply(stream, factor=2):
# ๊ฐ ํญ๋ชฉ์ factor ๊ณฑํ๊ธฐ
async for item in stream:
yield item * factor
async def process_pipeline():
# ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
source = data_source()
filtered = filter_even(source)
multiplied = multiply(filtered, 3)
# ๊ฒฐ๊ณผ ์๋น
async for result in multiplied:
print(f"๊ฒฐ๊ณผ: {result}")
# ์คํ
asyncio.run(process_pipeline())
โ
ํน์ง:
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- ๋์ฉ๋ ๋ฐ์ดํฐ์ ์ฒ๋ฆฌ์ ์ ํฉ
- ๋น๋๊ธฐ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
- ๋ฐฑํ๋ ์ ๊ด๋ฆฌ
- ์คํธ๋ฆผ ๋ณํ ๋ฐ ํํฐ๋ง
โ
AsyncIO ๋ชจ๋ฒ ์ฌ๋ก:
-
CPU ๋ฐ์ด๋ ์์
๋ถ๋ฆฌ: CPU ์ง์ฝ์ ์์
์
concurrent.futures.ProcessPoolExecutor
๋ก ์ฒ๋ฆฌ - ํ์์์ ์ค์ : ๋ชจ๋ ์ธ๋ถ ํธ์ถ์ ํ์์์ ์ ์ฉํ์ฌ ๋ฌดํ ๋๊ธฐ ๋ฐฉ์ง
-
๋๋ฒ๊น
ํ์ฑํ:
asyncio.run(main(), debug=True)
๋ก ๋๋ฒ๊น ๊ฐํ -
ํ์คํฌ ๊ทธ๋ฃนํ: ๊ด๋ จ ํ์คํฌ๋
asyncio.TaskGroup
๋๋asyncio.gather
๋ก ๊ทธ๋ฃนํ -
์ ์ ํ ์ทจ์ ์ฒ๋ฆฌ: ํ์คํฌ ์ทจ์ ์
try
/except asyncio.CancelledError
ํจํด ์ฌ์ฉ - ํ๋ก๋ฉํ ์ฐ์ค ๋ฐฉ์ง: ๋ฉ์ธ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ๋ธ๋กํนํ๋ ์ฝ๋ ํผํ๊ธฐ
- ๋ฐฑ์คํ ์ฌ์๋: ์ธ๋ถ ์๋น์ค ํธ์ถ ์ ์ง์ ๋ฐฑ์คํ ์ ์ฉ
-
์ปจํ
์คํธ ๊ด๋ฆฌ์ ํ์ฉ: ๋ฆฌ์์ค ๊ด๋ฆฌ์
async with
์ฌ์ฉ - ๊ตฌ์กฐํ๋ ๋์์ฑ: ๋ถ๋ชจ ํ์คํฌ๊ฐ ์์ ํ์คํฌ์ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
- ๋น๋๊ธฐ ์์ ์ทจ์: ๋ ์ด์ ํ์ ์๋ ํ์คํฌ๋ ๋ช ์์ ์ผ๋ก ์ทจ์
-
ํจ์จ์ ์ธ I/O ์ฒ๋ฆฌ: ํ์ผ I/O๋
aiofiles
์ฌ์ฉ, ๋คํธ์ํฌ๋aiohttp
์ฌ์ฉ - ์์ธ ์ฒ๋ฆฌ: ๋ชจ๋ ๋น๋๊ธฐ ์ฝ๋์ ์ ์ ํ ์์ธ ์ฒ๋ฆฌ ๊ตฌํ
- ์ฝ๋ ๊ฐ๋ ์ฑ ์ ์ง: ๋ณต์กํ ๋น๋๊ธฐ ๋ก์ง์ ํจ์๋ก ๋ถ๋ฆฌ
- ์ด๋ฒคํธ ๋ฃจํ ์ปค์คํฐ๋ง์ด์ง: ํ์์ ์ด๋ฒคํธ ๋ฃจํ ์ ์ฑ ์ปค์คํฐ๋ง์ด์ง
- ๋ก๊น ํตํฉ: ๋น๋๊ธฐ ์ฝ๋์๋ ์ผ๊ด๋ ๋ก๊น ์ ๋ต ์ ์ฉ