Ачааллж байна...
Энэ хичээлээр Бүлэг 14 дуусна. Тэр нь богино байх бөгөөд ганцхан асуултад хариулна:
"Async надад ХЭРЭГТЭЙ юу?"
Шинэ бичлэг байхгүй. Шинэ түлхүүр үг байхгүй. Зөвхөн ШИЙДВЭР.
Энэ бол Бүлэг 5.4 ("Аль бүтцийг хэзээ сонгох вэ") ба Бүлэг 7.4 ("Хэзээ inheritance хэрэглэх, хэзээ болих") -той ижил төрлийн хичээл: хүчирхэг хэрэгслийг ХЭЗЭЭ ашиглах, ХЭЗЭЭ БОЛИХ тухай.
Мөн энэ хичээлийн зорилго нь async -ийн айдсыг бүрмөсөн арилгах явдал юм.
Хамгийн эхлээд шууд, шударга хариулт өгье:
Ихэнх тохиолдолд — ҮГҮЙ. Танд async хэрэггүй.
Тэр нь худал биш, тайвшруулах гэсэн оролдлого ч биш.
Ихэнх Python программ нь async -гүйгээр бүрэн зөв ажилладаг.
Файл боловсруулах script → async хэрэггүй
Өгөгдөл шинжлэх → async хэрэггүй
Нэг API дуудах программ → async хэрэггүй
Автоматжуулалт, тайлан → async хэрэггүй
Курсийн бүх guided build → async хэрэггүй
Бүлэг 12.4-ийн цаг агаарын программ нь async -гүйгээр ТӨГС ажиллаж байна.
Тэгвэл хэзээ хэрэгтэй вэ?
Async хэрэгтэй эсэхийг мэдэхийн тулд гурван асуулт тавь. Гурвуулаа "тийм" байвал л async нь ашиг өгнө.
Асуулт 1: Ажил нь I/O-BOUND уу?
Хичээл 14.1-ээс:
I/O-bound — интернэт, диск, өгөгдлийн сан ХҮЛЭЭЖ байна
CPU-bound — жинхэнэ ТООЦООЛОЛ хийж байна
Хэрэв CPU-bound бол — async нь ЮУ Ч тусалахгүй. ЗОГС.
python
# CPU-bound — async нь УТГАГҮЙ
niilber = sum(i * i for i in range(100_000_000))
zurag = zurag_boloviruulakh(fail)
uguudul = shinjlekh(tom_hüsnegt)Async нь тооцооллыг хурдан болгодоггүй. Зөөгч хоёр гараараа хоёр хоол хийж чадахгүй.
Хэрэв танд жинхэнэ зэрэг тооцоолол хэрэгтэй бол — тэр нь multiprocessing (энэ курс үзэхгүй).
Асуулт 2: ОЛОН хүлээлт байна уу?
Хэрэв ЗӨВХӨН НЭГ хүсэлт байвал — async нь ЮУ Ч өгөхгүй.
python
# НЭГ хүсэлт — async нь утгагүй
hariult = requests.get(url, timeout=10)
uguudul = hariult.json()Тэр нь 0.5 секунд болно. Async -тэй ч 0.5 секунд болно.
Зөөгч НЭГ л ширээтэй бол — тэр нь гал тогоонд зогсож хүлээсэн ч, өөр газар явсан ч ялгаагүй. Хийх ажил байхгүй.
Async нь ЗӨВХӨН олон хүлээлт ДАВХЦАХ боломжтой үед л ашиг өгнө.
Асуулт 3: Хүлээлтүүд НЭГ НЭГЭЭСЭЭ ХАМААРАХГҮЙ юу?
Хамгийн нарийн асуулт.
python
# ХАМААРАЛГҮЙ — async ТУСАЛНА
tsag_agaar_UB = await avakh("Улаанбаатар")
tsag_agaar_Darkhan = await avakh("Дархан")
# Хоёулаа зэрэг эхэлж болноpython
# ХАМААРАЛТАЙ — async ТУСЛАХГҮЙ
kheregleagch = await kheregleagch_avakh(id)
zakhialga = await zakhialga_avakh(kheregleagch.id) # kheregleagch ХЭРЭГТЭЙ!Хоёр дахь тохиолдолд эхнийх нь дуусахгүйгээр хоёр дахь нь эхэлж чадахгүй. Тэдгээр нь ДАРААЛЛААР явах ЁСТОЙ.
Async нь тэднийг давхцуулж чадахгүй. Ямар ч ашиг байхгүй.
Зөөгчийн зүйрлэлээр: хэрэв нэг ширээ "эхлээд шөл, дараа нь үндсэн хоол" гэж захиалбал — зөөгч тэднийг зэрэг авчирч чадахгүй. Дараалал нь чухал.
Нөхцөл | Async ашиг өгөх үү |
|---|---|
CPU-bound тооцоолол | ҮГҮЙ — огт |
Нэг API дуудалт | ҮГҮЙ — утгагүй |
Дараалсан, хамааралтай хүсэлтүүд | ҮГҮЙ — давхцахгүй |
Олон ХАМААРАЛГҮЙ API дуудалт | ТИЙМ — том ашиг |
Олон хэрэглэгчид үйлчилдэг сервер | ТИЙМ — том ашиг |
Файл унших (жижиг) | ҮГҮЙ — хэт хурдан |
Олон мянган файл унших | Магадгүй |
Хамгийн ТОД ХОЁР тохиолдол:
Олон хамааралгүй I/O ажлыг ЗЭРЭГ хийх (Хичээл 14.2-ын таван хот)
Олон хэрэглэгчид зэрэг үйлчилдэг СЕРВЕР (FastAPI)
Одоо хамгийн чухал хэсэг рүү орно. Учир нь энэ курсийн зорилго нь FastAPI юм.
FastAPI-гийн documentation нь ЯГ ЮУ гэж хэлдэг вэ?
Тэр нь ойролцоогоор ингэж хэлдэг:
"Хэрэв та эргэлзэж байвал — ердийн
defашигла. Тэр нь ажиллана."
Тэр нь ХУДАЛ БИШ. Тэр нь ЖИНХЭНЭ зөвлөмж.
Ойлгохын тулд FastAPI-гийн дотоод механизмыг мэдэх хэрэгтэй.
Хэрэв та async def бичвэл:
python
@app.get("/nomnuud")
async def nomnuud_jagsaakh() -> list[Nom]:
nomnuud = await db.fetch_all(...) # async өгөгдлийн сан
return nomnuudFastAPI нь тэр функцийг EVENT LOOP дээр ажиллуулна (Хичээл 14.2-ын "зөөгч").
await дээр хүрэхэд — зөөгч нь өөр хэрэглэгч рүү шилжинэ.
Хэрэв та ердийн def бичвэл:
python
@app.get("/nomnuud")
def nomnuud_jagsaakh() -> list[Nom]:
nomnuud = db.fetch_all(...) # ердийн (блоклодог)
return nomnuudFastAPI нь тэр функцийг ТУСДАА АЖИЛЧИНД (thread pool) шилжүүлнэ.
Тэгэхээр тэр нь event loop -ыг БЛОКЛОХГҮЙ. Бусад хэрэглэгчид үргэлжлүүлэн үйлчлэгдэнэ.
ХОЁУЛАА АЖИЛЛАНА. FastAPI нь хоёуланг нь зөв зохицуулна.
async def:
Давуу тал: илүү үр ашигтай (thread хэрэггүй)
Сул тал: БҮХ дуудалт async байх ёстой
def:
Давуу тал: ЭНГИЙН, БҮХ САН ажиллана (requests, ердийн файл)
Сул тал: thread ашиглана (жаахан илүү нөөц)
Практикт ялгаа нь ХЭЗЭЭ мэдэгдэх вэ?
Зөвхөн МАШ ӨНДӨР ачаалалтай үед. Секундэд мянга, арван мянган хүсэлт.
Таны эхний хэдэн төсөлд — ялгаа нь МЭДЭГДЭХГҮЙ.
Одоо хамгийн чухал анхааруулгыг өгье.
async def бичээд, дотор нь БЛОКЛОДОГ зүйл дуудах — тэр нь ХАМГИЙН МУУ сонголт.
python
@app.get("/tsag-agaar")
async def tsag_agaar() -> dict: # ASYNC
hariult = requests.get(url, timeout=10) # БЛОКЛОДОГ!
return hariult.json()Юу болох вэ?
requests.get() нь event loop -ыг БҮРЭН БЛОКЛОНО. Зөөгч гал тогоонд зогсоно.
Тэр 0.5 секундын турш — ямар ч хэрэглэгч үйлчлэгдэхгүй. БҮГД хүлээнэ.
Тэр нь ердийн def -ээс ХАМААГҮЙ МУУ!
Учир нь ердийн def бол FastAPI нь түүнийг ТУСДАА ажилчинд шилжүүлдэг — бусад хэрэглэгч хөндөгдөхгүй.
Харьцуулъя:
python
# 1. ЗӨВ — ердийн def, блоклодог сан
@app.get("/tsag-agaar")
def tsag_agaar() -> dict:
hariult = requests.get(url, timeout=10)
return hariult.json()
# → FastAPI нь тусдаа thread -д шилжүүлнэ. Бусад хэрэглэгч хөндөгдөхгүй. ✓
# 2. ЗӨВ — async def, async сан
@app.get("/tsag-agaar")
async def tsag_agaar() -> dict:
async with httpx.AsyncClient() as client:
hariult = await client.get(url, timeout=10)
return hariult.json()
# → Event loop нь солигдоно. Хамгийн үр ашигтай. ✓
# 3. АЙМШИГТАЙ — async def, БЛОКЛОДОГ сан
@app.get("/tsag-agaar")
async def tsag_agaar() -> dict:
hariult = requests.get(url, timeout=10) # БЛОКЛОНО!
return hariult.json()
# → БҮХ хэрэглэгч блоклогдоно. ХАМГИЙН МУУ. ✗ГОЛ ДҮРЭМ:
async defбичвэл — ДОТОР НЬ БҮГД async байх ЁСТОЙ.Хэрэв блоклодог сан ашиглаж байвал — ердийн
defбич.
Тэр нь энэ хичээлийн ХАМГИЙН чухал өгүүлбэр.
Одоо бүх зүйлийг НЭГ энгийн дүрэм болгоё.
Та FastAPI endpoint бичиж байна.
Асуулт: Endpoint дотор ЮУ дуудаж байна вэ?
├── Зөвхөн санах ойд ажиллана (list, dict, тооцоолол)
│ → def эсвэл async def — ХАМААГҮЙ. Аль нь ч болно.
│
├── БЛОКЛОДОГ сан (requests, ердийн файл, sync ДС)
│ → ЕРДИЙН def. ЗААВАЛ.
│
└── ASYNC сан (httpx, async ДС)
→ async def. ЗААВАЛ.Тэр л болоо.
Санамж: САН нь шийднэ, ТА биш.
requests ашиглаж байна уу → def
httpx (async горим) ашиглаж байна уу → async def
Одоо практик асуулт: Бүлэг 15-д та ямар кодыг бичих вэ?
Хариулт: ЕРДИЙН def.
Яагаад?
Тэр нь ЭНГИЙН. Та async, await, gather, event loop -ыг бодох шаардлагагүй.
Бидний capstone нь өгөгдлийн сан ашиглахгүй — зөвхөн санах ойд байгаа жагсаалт. Ямар ч хүлээлт байхгүй.
Ямар ч ялгаа гарахгүй. Ганц хэрэглэгч (та), гурван endpoint.
FastAPI нь бүрэн зөв ажиллана.
python
@app.get("/nomnuud")
def nomnuud_jagsaakh() -> list[Nom]:
return nomnuud # санах ойн жагсаалтЭнгийн, тод, зөв.
Хэрэв та ирээдүйд өгөгдлийн сантай, олон хэрэглэгчтэй, өндөр ачаалалтай систем бичвэл — тэр үед async -ыг судлаарай. Тэр үед та бэлэн байх болно.
Практик дохионууд:
1. Та ХЭМЖИЖ, УДААН гэдгийг ОЛСОН.
Бүлэг 10.3-ын цаг хэмжигч decorator -ыг ашиглаарай. Хэрэв I/O нь бүх цагийг идэж байвал — async нь тусалж болно.
Хэмжихээсээ өмнө оптимизаци ХИЙЖ БОЛОХГҮЙ. Бүлэг 5.4-ийн сургамж:
"Эрт оптимизаци бүү хий."
2. Танд ОЛОН ХАМААРАЛГҮЙ хүсэлт байна.
Таван хот, зуун API дуудалт — тэр үед async нь тод ашиг өгнө.
3. Таны сервер ӨНДӨР АЧААЛАЛТАЙ.
Секундэд мянга, арван мянган хүсэлт. Тэр үед thread -ийн нөөц асуудал болж эхэлнэ.
Эдгээрийн НЭГ Ч гараагүй бол — async бүү сурч цаг үр.
Нэг практик зөвлөгөө: async нь цорын ганц шийдэл БИШ.
Хэрэв танд олон API дуудалт хэрэгтэй, гэхдээ async -тэй холбогдох хүсэлгүй бол — thread ашиглаж болно:
python
from concurrent.futures import ThreadPoolExecutor
import requests
import time
def tsag_agaar_avakh(khot: tuple[float, float, str]) -> tuple[str, float]:
lat, lon, ner = khot
hariult = requests.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": lat,
"longitude": lon,
"current": "temperature_2m",
"timezone": "auto",
},
timeout=10,
)
temp = hariult.json()["current"]["temperature_2m"]
return (ner, temp)
KHOTUUD = [
(47.92, 106.92, "Улаанбаатар"),
(49.49, 105.92, "Дархан"),
(49.03, 104.08, "Эрдэнэт"),
(35.68, 139.69, "Токио"),
(51.51, -0.13, "Лондон"),
]
ekhelsen = time.time()
with ThreadPoolExecutor(max_workers=5) as executor:
ur_dun = list(executor.map(tsag_agaar_avakh, KHOTUUD))
duussan = time.time()
for ner, temp in ur_dun:
print(f"{ner:<15} {temp:>6.1f}°C")
print(f"\nНийт: {duussan - ekhelsen:.2f} секунд")Улаанбаатар 18.7°C
Дархан 17.2°C
Эрдэнэт 16.9°C
Токио 28.4°C
Лондон 21.3°C
Нийт: 0.61 секунд0.61 секунд — async -тэй БАРАГ ИЖИЛ!
Гэвч:
async, await, gather, event loop — ЮУ Ч БАЙХГҮЙ
requests -ыг ашиглаж байна (өөр сан хэрэггүй!)
Функц нь ЕРДИЙН def
with — Бүлэг 13.3-ын context manager
ThreadPoolExecutor нь таван "ажилчин" үүсгэж, тэдгээр нь хүсэлтүүдийг зэрэг илгээж байна.
Тэр нь async -ээс жаахан илүү нөөц иддэг (thread нь coroutine -ээс "хүнд"), гэхдээ олон зуун хүсэлт хүртэл ялгаа нь мэдэгдэхгүй.
Практик зөвлөгөө:
Хэрэв танд олон I/O ажлыг зэрэг хийх хэрэгтэй бол — ЭХЛЭЭД
ThreadPoolExecutor-ыг оролдоорой.Тэр нь async -ээс ХАМААГҮЙ ЭНГИЙН, ижил төстэй үр дүн өгнө.
Async -ыг зөвхөн ThreadPoolExecutor хангалтгүй болоход л сонго. Тэр нь ихэвчлэн хэзээ ч болдоггүй.
Эцэст нь, энэ бүлгийн зорилгыг биелүүлье.
Async нь АЙМШИГТАЙ БИШ.
Тэр нь:
Гурван түлхүүр үг: async def, await, asyncio.run()
Нэг санаа: хүлээж байхдаа өөр ажил хий
Нэг дүрэм: блоклодог зүйл бичиж болохгүй
Тэр л болоо.
Хэрэв та FastAPI-гийн documentation дээр async def харвал — та түүнийг уншиж чадна.
Хэрэв та түүнийг бичих ШААРДЛАГАТАЙ бол — та бичиж чадна.
Гэхдээ ихэнх тохиолдолд — та түүнийг бичихгүй. Тэр нь БҮРЭН ЗҮГЭЭР.
Async -ыг мэдэхгүй нь Python программист болоход саад БИШ.
Async -ыг ХЭРЭГГҮЙ газарт ашиглах нь илүү муу.
Хэрэв сонирхвол: дээрх ThreadPoolExecutor -ийн кодыг ажиллуулж, Хичээл 14.2-ын async кодтой харьцуулаарай. Хугацаа нь бараг ижил, гэхдээ код нь ХАМААГҮЙ энгийн.
Тэр харьцуулалт нь энэ хичээлийн бүх санааг харуулна.
Мөн хүсвэл: CPU-bound ажлыг ThreadPoolExecutor -ээр туршиж үзээрэй:
python
def khund_ajil(n: int) -> int:
return sum(i * i for i in range(n))
with ThreadPoolExecutor(max_workers=5) as executor:
ur_dun = list(executor.map(khund_ajil, [10_000_000] * 5))Хугацаа нь БАРАГ БУУРАХГҮЙ. Учир нь CPU-bound ажилд thread ч бас тусалдаггүй (Python-ы GIL гэдэг механизмаас болж).
CPU-bound → multiprocessing. Гэхдээ тэр нь өөр сэдэв.
ШУУД ХАРИУЛТ: Ихэнх тохиолдолд танд async ХЭРЭГГҮЙ.
ГУРВАН АСУУЛТ — гурвуулаа "тийм" байвал л async ашиг өгнө:
Ажил нь I/O-bound уу? (CPU-bound → ЗОГС, async туслахгүй)
ОЛОН хүлээлт байна уу? (нэг хүсэлт → утгагүй)
Хүлээлтүүд ХАМААРАЛГҮЙ юу? (дараалсан, хамааралтай → давхцахгүй)
Хамгийн ТОД хоёр тохиолдол: олон хамааралгүй API дуудалт, олон хэрэглэгчид үйлчилдэг сервер.
FASTAPI-ГИЙН АЛБАН ЁСНЫ БАЙР СУУРЬ: "Эргэлзэж байвал — ердийн def ашигла."
async def → FastAPI нь event loop дээр ажиллуулна
def → FastAPI нь ТУСДАА ажилчинд шилжүүлнэ
ХОЁУЛАА АЖИЛЛАНА.
ХАМГИЙН АЮУЛТАЙ АЛДАА: async def + БЛОКЛОДОГ сан (requests).
Event loop -ыг БҮРЭН блоклоно → БҮХ хэрэглэгч хүлээнэ
Тэр нь ердийн def -ээс ХАМААГҮЙ МУУ
ГОЛ ДҮРЭМ:
async defбичвэл — дотор нь БҮГД async байх ЁСТОЙ.
Блоклодог сан ашиглаж байвал — ердийнdefбич.
САН нь шийднэ, ТА биш.
Бүлэг 15-ын capstone: ЕРДИЙН def. Энгийн, тод, зөв. Ямар ч ялгаа гарахгүй.
ThreadPoolExecutor — async -гүйгээр зэрэг ажиллуулах арга.
requests -ыг ашиглаж болно! Өөр сан хэрэггүй.
Хугацаа нь async -тэй БАРАГ ИЖИЛ (0.61с vs 0.58с)
Хамаагүй ЭНГИЙН
Эхлээд ҮҮНИЙГ оролд. Async -ыг зөвхөн энэ хангалтгүй болоход л сонго.
Эрт оптимизаци бүү хий. Эхлээд ХЭМЖ (Бүлэг 10.3-ын цаг хэмжигч), дараа нь шийд.
Async -ыг мэдэхгүй нь Python программист болоход саад БИШ. Хэрэггүй газарт ашиглах нь илүү муу.
Бүлэг 14 дууслаа. Async -ийн айдас арилав.
БҮЛЭГ 15 — CAPSTONE.
Одоо бид энэ курсийн бүх замын төгсгөлд ирлээ.
Хичээл 15.1: Framework ба library — ялгаа нь юу вэ? Тэнд бид Бүлэг 1.1-ийн амлалтыг биелүүлж, "framework-д бэлэн" гэдэг нь ЯГ ЮУ гэсэн үг болохыг бүрэн тайлбарлана.
Хичээл 15.2 — CAPSTONE: та ӨӨРИЙН FastAPI ПРОГРАММ бичнэ. Шинэ venv, pip install fastapi uvicorn, endpoint-ууд, Pydantic class-ууд. Дараа нь uvicorn -оор ажиллуулж, browser-ээр нээнэ.
Тэгээд /docs хуудсыг нээнэ.
Тэнд та өөрийн бичсэн TYPE HINT -үүдээс АВТОМАТААР үүссэн, БҮРЭН ИНТЕРАКТИВ баримт бичгийг харна. Товчлуур дарж, өөрийн API -г ТЭР ДОР НЬ туршиж болно.
Тэр мөч — энэ бүх курсийн ШАГНАЛ юм.
Хичээл 15.3: Documentation уншиж сурах — мета-ур чадвар.
Хичээл 15.4: Баяр хүргэе ба цаашдын зам.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.