Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Asinxron iteratsiya
- 2.2. Asinxron kontekst menejer
- 2.3. asyncio.Queue
- 2.4. asyncio'da poyga holatlari
- 2.5. Sinxronlash vositalari
- 2.6. Stream lar — tarmoq
- 2.7. Asinxron subprocess
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Asinxron iterator va kontekst menejer
- Misol 2 — asyncio.Queue bilan quvur
- Misol 3 — asyncio'dagi poyga va sinxronlash
- Misol 4 — Amaliy: kalit-qiymat TCP serveri
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
14.7-dars: async / await amaliyoti
14-QISM — KONKURENTLIK VA PARALLELLIK · 7-dars
1. Kirish va motivatsiya
14.6-darsda hodisa siklining ichki mexanizmini ko'rdik. Endi savol boshqa: haqiqiy asinxron dastur qanday quriladi?
Faqat async def va await yetmaydi. Real dasturda yana:
- ma'lumot oqimini asinxron iterator bilan o'qish,
- ulanishlarni asinxron kontekst menejer bilan ochib-yopish,
- ishlab chiqaruvchi va iste'molchini
asyncio.Queuebilan bog'lash, - umumiy holatni
Lock,Event,Semaphorebilan himoya qilish, - tarmoq bilan stream lar orqali gaplashish kerak.
Real vaziyat. Jamoa asinxron botni yozdi va "asyncio'da poyga holati bo'lmaydi, chunki bitta ip" deb o'yladi. Ishlab chiqarishda foydalanuvchi balanslari tasodifiy kamayib ketdi: balans = await ol(); await saqla(balans + summa) — ikki await orasida boshqa vazifa o'sha balansni o'zgartirib ulgurgan edi. Bitta asyncio.Lock muammoni hal qildi.
Bu darsda asinxron dasturning "g'ishtlari"ni o'rganamiz va oxirida ulardan haqiqiy TCP server quramiz.
Bu darsda:
- Asinxron iterator va generator:
async for,anext,aclosing - Asinxron kontekst menejer:
__aenter__/__aexit__,asynccontextmanager -
asyncio.Queue: ishlab chiqaruvchi → iste'molchi quvuri - asyncio'dagi poyga holatlari va
Lock,Event,Semaphore - Stream lar:
start_server,open_connection - Asinxron subprocess
- Amaliy: kalit-qiymat TCP serveri
2. Nazariya — chuqur tushuntirish
2.1. Asinxron iteratsiya
| Sinxron | Asinxron |
|---|---|
__iter__ / __next__ |
__aiter__ / __anext__ |
for x in it |
async for x in it |
next(it) |
await anext(it) |
StopIteration |
StopAsyncIteration |
[x for x in it] |
[x async for x in it] |
Asinxron generator — async def ichida yield:
async def satrlar(ulanish):
while (satr := await ulanish.readline()):
yield satr.decode()
async for satr in satrlar(ulanish):
... Asinxron generatorni o'rtada tashlab ketsangiz, uning finally bloki darhol bajarilmasligi mumkin. Tozalashni kafolatlash uchun:
async with contextlib.aclosing(satrlar(ulanish)) as oqim:
async for satr in oqim:
if satr == "STOP":
break # finally shu yerda bajariladi2.2. Asinxron kontekst menejer
class Ulanish:
async def __aenter__(self):
await self.och()
return self
async def __aexit__(self, tur, qiymat, iz):
await self.yop()
return False # istisnoni yutmaymiz
@contextlib.asynccontextmanager
async def tranzaksiya(db):
await db.boshla()
try:
yield db
await db.tasdiqla()
except BaseException:
await db.bekor_qil()
raise| Vosita | Qachon |
|---|---|
Klass (__aenter__/__aexit__) |
Holatli, qayta ishlatiladigan resurs |
@asynccontextmanager |
Qisqa, bir martalik ochish-yopish |
AsyncExitStack |
Dinamik sonli resurslar |
2.3. asyncio.Queue
navbat: asyncio.Queue[int] = asyncio.Queue(maxsize=100)
await navbat.put(x) # to'lsa kutadi — ⭐ tabiiy orqa bosim
x = await navbat.get() # bo'sh bo'lsa kutadi
navbat.task_done()
await navbat.join() # hamma element ishlanguncha kutadi| Tur | Tartib |
|---|---|
Queue |
FIFO |
LifoQueue |
LIFO |
PriorityQueue |
Eng kichik birinchi |
maxsize — orqa bosim (backpressure): ishlab chiqaruvchi iste'molchidan tez bo'lsa, put kutib qoladi va xotira cheksiz o'smaydi.
asyncio.Queue ip-xavfsiz emas — faqat bitta loop ichida ishlating. Iplar orasida — queue.Queue (14.3-dars).
2.4. asyncio'da poyga holatlari
"Bitta ip — poyga yo'q" — noto'g'ri. Poyga har bir await da yuz berishi mumkin:
balans = hisob.balans # o'qish
await asyncio.sleep(0) # ⚠️ shu yerda boshqa vazifa ishlaydi
hisob.balans = balans + 100 # eskirgan qiymat ustiga yozish| Holat | Poyga bormi |
|---|---|
await siz ketma-ket qatorlar |
Yo'q — atomar |
O'qish → await → yozish |
Bor |
Faqat bitta await siz o'zgartirish (x += 1) |
Yo'q |
Iplardan farqi: xavfli joylar ko'rinib turadi — ular faqat await lar.
2.5. Sinxronlash vositalari
| Vosita | Vazifasi |
|---|---|
asyncio.Lock |
Bir vaqtda bitta vazifa |
asyncio.Semaphore(n) |
Bir vaqtda ko'pi bilan n ta |
asyncio.BoundedSemaphore(n) |
Ortiqcha release da xato beradi |
asyncio.Event |
"Signal berildi" belgisi — ko'p vazifani uyg'otadi |
asyncio.Condition |
Shart bajarilishini kutish |
asyncio.Barrier(n) |
n vazifa yig'ilguncha kutish (3.11+) |
asyncio.Lock va threading.Lock almashtirib bo'lmaydi: threading.Lock loopni bloklaydi.
2.6. Stream lar — tarmoq
# Server
async def ishlovchi(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
satr = await reader.readline()
writer.write(javob)
await writer.drain() # ⭐ bufer to'lsa kutadi
writer.close()
await writer.wait_closed()
server = await asyncio.start_server(ishlovchi, "127.0.0.1", 8000)
async with server:
await server.serve_forever()
# Mijoz
reader, writer = await asyncio.open_connection("127.0.0.1", 8000)| Metod | Izoh |
|---|---|
reader.readline() |
\n gacha; ulanish yopilsa b"" |
reader.readexactly(n) |
Aynan n bayt |
writer.write(b) |
Buferga yozadi (kutmaydi) |
await writer.drain() |
Orqa bosim — buferni bo'shatishni kutadi |
2.7. Asinxron subprocess
jarayon = await asyncio.create_subprocess_exec(
"git", "status", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
chiqish, xato = await jarayon.communicate()Loopni bloklamasdan tashqi dasturlarni ishga tushirish — o'nlab buyruqni parallel bajarish uchun qulay (26-qism).
3. Tez ma'lumotnoma
async for x in asinxron_generator(): ...
async with contextlib.aclosing(gen()) as g: ...
async with Resurs() as r: ...
navbat = asyncio.Queue(maxsize=100)
await navbat.put(x); x = await navbat.get(); navbat.task_done(); await navbat.join()
qulf = asyncio.Lock()
async with qulf: ...
reader, writer = await asyncio.open_connection(host, port)
server = await asyncio.start_server(ishlovchi, host, port)Qoidalar
har await — navbat almashish nuqtasi
o'qish → await → yozish = poyga → asyncio.Lock
Queue(maxsize) — orqa bosim
writer.write dan keyin await writer.drain()
asinxron generator tozalanishi — aclosing4. Batafsil misollar
Misol 1 — Asinxron iterator va kontekst menejer
"""async for va asinxron generator; anext; asinxron comprehension; __aenter__/__aexit__; asynccontextmanager; aclosing."""
import asyncio
import contextlib
from collections.abc import AsyncIterator
async def sanoq(n: int) -> AsyncIterator[int]:
for i in range(n):
await asyncio.sleep(0) # masalan, tarmoqdan keyingi bo'lakni kutish
yield i
class Sahifalar:
"""Qo'lda yozilgan asinxron iterator: API ni sahifama-sahifa o'qiydi."""
def __init__(self, jami: int, hajm: int) -> None:
self.jami, self.hajm, self.joriy = jami, hajm, 0
def __aiter__(self) -> "Sahifalar":
return self
async def __anext__(self) -> list[int]:
if self.joriy >= self.jami:
raise StopAsyncIteration
await asyncio.sleep(0)
sahifa = list(range(self.joriy, min(self.joriy + self.hajm, self.jami)))
self.joriy += self.hajm
return sahifa
class Ulanish:
def __init__(self, jurnal: list[str]) -> None:
self.jurnal = jurnal
async def __aenter__(self) -> "Ulanish":
await asyncio.sleep(0)
self.jurnal.append("ochildi")
return self
async def __aexit__(self, tur: type[BaseException] | None, *_: object) -> bool:
await asyncio.sleep(0)
self.jurnal.append(f"yopildi (xato bilan: {tur is not None})")
return False
@contextlib.asynccontextmanager
async def tranzaksiya(jurnal: list[str]) -> AsyncIterator[str]:
jurnal.append("BEGIN")
try:
yield "tx-1"
jurnal.append("COMMIT")
except BaseException:
jurnal.append("ROLLBACK")
raise
async def main() -> None:
print("=== 1. Asinxron generator ===")
print(f" async comprehension: {[x async for x in sanoq(5)]}")
oqim = sanoq(2)
print(f" anext: {await anext(oqim)}, {await anext(oqim)}")
try:
await anext(oqim)
except StopAsyncIteration:
print(" tugagach: StopAsyncIteration")
print(f" turi: {type(sanoq(1)).__name__}")
print("\n=== 2. Qo'lda yozilgan asinxron iterator ===")
async for sahifa in Sahifalar(jami=7, hajm=3):
print(f" sahifa: {sahifa}")
print("\n=== 3. __aenter__ / __aexit__ ===")
jurnal: list[str] = []
async with Ulanish(jurnal):
jurnal.append("ishlatildi")
try:
async with Ulanish(jurnal):
raise ValueError("so'rov buzilgan")
except ValueError:
jurnal.append("xato tashqarida ushlandi")
for qadam in jurnal:
print(f" {qadam}")
print("\n=== 4. asynccontextmanager ===")
for buzilsinmi in (False, True):
jurnal = []
try:
async with tranzaksiya(jurnal) as tx:
jurnal.append(f"{tx}: yozildi")
if buzilsinmi:
raise RuntimeError("disk to'ldi")
except RuntimeError:
pass
print(f" xato={buzilsinmi}: {jurnal}")
print("\n=== 5. aclosing: generator tozalanishi ===")
tozalash: list[str] = []
async def fayl_oqimi() -> AsyncIterator[int]:
try:
for i in range(1_000):
yield i
finally:
tozalash.append("fayl yopildi")
async with contextlib.aclosing(fayl_oqimi()) as satrlar:
async for satr in satrlar:
if satr == 2:
break
print(f" break dan keyin darhol: {tozalash}")
print(" ⭐ aclosing — finally bloki kafolatlangan vaqtda bajariladi")
if __name__ == "__main__":
asyncio.run(main())Natijaning muhim qismi:
=== 1. Asinxron generator ===
async comprehension: [0, 1, 2, 3, 4]
anext: 0, 1
tugagach: StopAsyncIteration
turi: async_generator
=== 2. Qo'lda yozilgan asinxron iterator ===
sahifa: [0, 1, 2]
sahifa: [3, 4, 5]
sahifa: [6]
=== 3. __aenter__ / __aexit__ ===
ochildi
ishlatildi
yopildi (xato bilan: False)
ochildi
yopildi (xato bilan: True)
xato tashqarida ushlandi
=== 4. asynccontextmanager ===
xato=False: ['BEGIN', 'tx-1: yozildi', 'COMMIT']
xato=True: ['BEGIN', 'tx-1: yozildi', 'ROLLBACK']
=== 5. aclosing: generator tozalanishi ===
break dan keyin darhol: ['fayl yopildi']
⭐ aclosing — finally bloki kafolatlangan vaqtda bajariladiNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — asyncio.Queue bilan quvur
"""Ishlab chiqaruvchi → iste'molchilar; task_done/join; maxsize bilan orqa bosim; to'xtatish signali; PriorityQueue."""
import asyncio
import time
TUGADI = None
async def ishlab_chiqaruvchi(navbat: asyncio.Queue[int | None], soni: int, jurnal: list[str]) -> None:
for i in range(soni):
await navbat.put(i) # to'lsa shu yerda kutadi
jurnal.append(f"put {i} (navbatda {navbat.qsize()})")
async def iste_molchi(nom: str, navbat: asyncio.Queue[int | None], natijalar: dict[str, list[int]]) -> None:
while True:
element = await navbat.get()
try:
if element is TUGADI:
return
await asyncio.sleep(0.01) # sekin ishlov
natijalar.setdefault(nom, []).append(element * element)
finally:
navbat.task_done()
async def quvur() -> None:
navbat: asyncio.Queue[int | None] = asyncio.Queue(maxsize=4)
natijalar: dict[str, list[int]] = {}
jurnal: list[str] = []
iste_molchilar = [asyncio.create_task(iste_molchi(f"ishchi-{i}", navbat, natijalar)) for i in range(3)]
bosh = time.perf_counter()
await ishlab_chiqaruvchi(navbat, 30, jurnal)
await navbat.join() # ⭐ hamma element ishlandi
oraliq = time.perf_counter() - bosh
for _ in iste_molchilar:
await navbat.put(TUGADI) # har ishchiga to'xtash signali
await asyncio.gather(*iste_molchilar)
hammasi = sorted(x for royxat in natijalar.values() for x in royxat)
print(f" 30 element ishlandi: {hammasi == [i * i for i in range(30)]}")
print(f" ishni 3 ishchi bo'lishdi: {len(natijalar) == 3}")
print(f" ketma-ket 0.3 s bo'lardi, parallel 0.2 s dan kam: {oraliq < 0.2}")
eng_kop = max(int(qator.split("navbatda ")[1].rstrip(")")) for qator in jurnal)
print(f" navbatda eng ko'p element: {eng_kop} (maxsize=4)")
print(f" ⭐ orqa bosim ishladi — navbat chegaradan oshmadi: {eng_kop <= 4}")
print(f" ishchilar to'xtadi: {all(t.done() for t in iste_molchilar)}")
async def ustuvorlik() -> None:
navbat: asyncio.PriorityQueue[tuple[int, str]] = asyncio.PriorityQueue()
for vazifa in [(3, "hisobot"), (1, "to'lov"), (2, "xabarnoma"), (1, "xavfsizlik")]:
await navbat.put(vazifa)
tartib = [(await navbat.get())[1] for _ in range(navbat.qsize())]
print(f" bajarilish tartibi: {tartib}")
print(" ⭐ bir xil ustuvorlikda ikkinchi element (satr) solishtiriladi")
async def main() -> None:
print("=== 1. Quvur: 1 ishlab chiqaruvchi → 3 iste'molchi ===")
await quvur()
print("\n=== 2. PriorityQueue ===")
await ustuvorlik()
if __name__ == "__main__":
asyncio.run(main())Natijaning muhim qismi:
=== 1. Quvur: 1 ishlab chiqaruvchi → 3 iste'molchi ===
30 element ishlandi: True
ishni 3 ishchi bo'lishdi: True
ketma-ket 0.3 s bo'lardi, parallel 0.2 s dan kam: True
navbatda eng ko'p element: 4 (maxsize=4)
⭐ orqa bosim ishladi — navbat chegaradan oshmadi: True
ishchilar to'xtadi: True
=== 2. PriorityQueue ===
bajarilish tartibi: ["to'lov", 'xavfsizlik', 'xabarnoma', 'hisobot']
⭐ bir xil ustuvorlikda ikkinchi element (satr) solishtiriladiNima ko'rsatdi: 2.3-bo'lim.
Misol 3 — asyncio'dagi poyga va sinxronlash
"""await orasidagi poyga; Lock bilan tuzatish; await siz kod atomar; Event; Semaphore; Condition."""
import asyncio
class Hisob:
def __init__(self) -> None:
self.balans = 0
self.qulf = asyncio.Lock()
async def xavfli_toldirish(hisob: Hisob) -> None:
for _ in range(1_000):
joriy = hisob.balans
await asyncio.sleep(0) # masalan, bazaga yozish
hisob.balans = joriy + 1
async def xavfsiz_toldirish(hisob: Hisob) -> None:
for _ in range(1_000):
async with hisob.qulf:
joriy = hisob.balans
await asyncio.sleep(0)
hisob.balans = joriy + 1
async def awaitsiz_toldirish(hisob: Hisob) -> None:
for _ in range(1_000):
hisob.balans += 1 # await yo'q — atomar
if _ % 100 == 0:
await asyncio.sleep(0)
async def poyga() -> None:
for nom, funksiya in [("xavfli", xavfli_toldirish), ("Lock bilan", xavfsiz_toldirish),
("await siz", awaitsiz_toldirish)]:
hisob = Hisob()
await asyncio.gather(*(funksiya(hisob) for _ in range(5)))
print(f" {nom:11} → balans {hisob.balans:>5} / 5000, yo'qolgan: {5_000 - hisob.balans}")
print(" ⚠️ bitta ip ham poygadan himoya qilmaydi — xavf await da")
async def hodisa() -> None:
tayyor = asyncio.Event()
uyg_ongan: list[int] = []
async def kutuvchi(n: int) -> None:
await tayyor.wait()
uyg_ongan.append(n)
vazifalar = [asyncio.create_task(kutuvchi(i)) for i in range(4)]
await asyncio.sleep(0.01)
print(f" set() dan oldin uyg'onganlar: {uyg_ongan}")
tayyor.set()
await asyncio.gather(*vazifalar)
print(f" set() dan keyin: {sorted(uyg_ongan)} — hammasi bir signal bilan")
async def semafor() -> None:
chegara = asyncio.Semaphore(3)
faol = eng_kop = 0
async def yukla(i: int) -> int:
nonlocal faol, eng_kop
async with chegara:
faol += 1
eng_kop = max(eng_kop, faol)
await asyncio.sleep(0.01)
faol -= 1
return i
natijalar = await asyncio.gather(*(yukla(i) for i in range(12)))
print(f" 12 vazifa bajarildi: {natijalar == list(range(12))}")
print(f" bir vaqtda eng ko'p faol: {eng_kop} (Semaphore(3))")
async def shart() -> None:
shart_obyekt = asyncio.Condition()
ombor: list[str] = []
olinganlar: list[str] = []
async def xaridor(nom: str) -> None:
async with shart_obyekt:
await shart_obyekt.wait_for(lambda: len(ombor) > 0)
olinganlar.append(f"{nom}:{ombor.pop(0)}")
xaridorlar = [asyncio.create_task(xaridor(f"x{i}")) for i in range(2)]
await asyncio.sleep(0.01)
for mahsulot in ("olma", "nok"):
async with shart_obyekt:
ombor.append(mahsulot)
shart_obyekt.notify()
await asyncio.sleep(0.01)
await asyncio.gather(*xaridorlar)
print(f" olingan mahsulotlar: {sorted(o.split(':')[1] for o in olinganlar)}")
print(f" ombor bo'sh: {ombor == []}")
async def main() -> None:
print("=== 1. Poyga holati ===")
await poyga()
print("\n=== 2. Event ===")
await hodisa()
print("\n=== 3. Semaphore ===")
await semafor()
print("\n=== 4. Condition ===")
await shart()
if __name__ == "__main__":
asyncio.run(main())Natijaning muhim qismi:
=== 1. Poyga holati ===
xavfli → balans 1000 / 5000, yo'qolgan: 4000
Lock bilan → balans 5000 / 5000, yo'qolgan: 0
await siz → balans 5000 / 5000, yo'qolgan: 0
⚠️ bitta ip ham poygadan himoya qilmaydi — xavf await da
=== 2. Event ===
set() dan oldin uyg'onganlar: []
set() dan keyin: [0, 1, 2, 3] — hammasi bir signal bilan
=== 3. Semaphore ===
12 vazifa bajarildi: True
bir vaqtda eng ko'p faol: 3 (Semaphore(3))
=== 4. Condition ===
olingan mahsulotlar: ['nok', 'olma']
ombor bo'sh: TrueNima ko'rsatdi: 2.4, 2.5-bo'limlar.
Misol 4 — Amaliy: kalit-qiymat TCP serveri
Hamma g'ishtlarni birlashtiramiz: haqiqiy TCP server (127.0.0.1, operatsion tizim tanlagan port), matnli protokol (SET, GET, DEL, KEYS), umumiy ombor uchun Lock, ulanishlar soni uchun Semaphore, bo'sh turgan mijozlar uchun muddat, bir vaqtda ishlaydigan mijozlar va xushmuomala to'xtatish.
"""asyncio stream lari bilan haqiqiy TCP server; protokol; Lock; ulanish chegarasi; muddat; parallel mijozlar; subprocess mijoz."""
import asyncio
import sys
class KVServer:
def __init__(self, maks_ulanish: int = 20, bosh_turish: float = 0.3) -> None:
self.ombor: dict[str, str] = {}
self.qulf = asyncio.Lock()
self.chegara = asyncio.Semaphore(maks_ulanish)
self.bosh_turish = bosh_turish
self.statistika = {"ulanishlar": 0, "buyruqlar": 0, "muddat": 0}
async def bajar(self, satr: str) -> str:
qismlar = satr.split(maxsplit=2)
if not qismlar:
return "XATO bo'sh buyruq"
buyruq, *argumentlar = qismlar
async with self.qulf:
match buyruq.upper(), argumentlar:
case "SET", [kalit, qiymat]:
self.ombor[kalit] = qiymat
return "OK"
case "GET", [kalit]:
return self.ombor.get(kalit, "YO'Q")
case "DEL", [kalit]:
return "OK" if self.ombor.pop(kalit, None) is not None else "YO'Q"
case "KEYS", []:
return " ".join(sorted(self.ombor)) or "(bo'sh)"
case _:
return f"XATO noma'lum buyruq: {satr}"
async def ishlovchi(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
async with self.chegara:
self.statistika["ulanishlar"] += 1
try:
while True:
try:
async with asyncio.timeout(self.bosh_turish):
xom = await reader.readline()
except TimeoutError:
self.statistika["muddat"] += 1
writer.write("XAYR muddat tugadi\n".encode())
await writer.drain()
break
if not xom:
break
self.statistika["buyruqlar"] += 1
writer.write((await self.bajar(xom.decode().strip()) + "\n").encode())
await writer.drain()
finally:
writer.close()
await writer.wait_closed()
async def mijoz(port: int, buyruqlar: list[str]) -> list[str]:
reader, writer = await asyncio.open_connection("127.0.0.1", port)
javoblar = []
for buyruq in buyruqlar:
writer.write(f"{buyruq}\n".encode())
await writer.drain()
javoblar.append((await reader.readline()).decode().strip())
writer.close()
await writer.wait_closed()
return javoblar
TASHQI_MIJOZ = """
import socket, sys
s = socket.create_connection(("127.0.0.1", int(sys.argv[1])))
f = s.makefile("rw", encoding="utf-8", newline="\\n")
for b in ["SET tashqi jarayon", "GET tashqi"]:
f.write(b + "\\n"); f.flush()
print(f.readline().strip())
"""
async def main() -> None:
kv = KVServer()
server = await asyncio.start_server(kv.ishlovchi, "127.0.0.1", 0)
port = server.sockets[0].getsockname()[1]
async with server:
print("=== 1. Bitta mijoz ===")
javoblar = await mijoz(port, ["SET til python", "GET til", "GET yoq", "DEL til", "GET til", "SALOM"])
for javob in javoblar:
print(f" {javob}")
print("\n=== 2. 50 ta mijoz bir vaqtda ===")
vazifalar = [mijoz(port, [f"SET k{i:02d} {i * i}", f"GET k{i:02d}"]) for i in range(50)]
natijalar = await asyncio.gather(*vazifalar)
print(f" hamma SET javobi OK: {all(n[0] == 'OK' for n in natijalar)}")
print(f" hamma GET o'z qiymatini oldi: {all(n[1] == str(i * i) for i, n in enumerate(natijalar))}")
kalitlar = (await mijoz(port, ["KEYS"]))[0].split()
print(f" ombordagi kalitlar: {len(kalitlar)}, birinchilari: {kalitlar[:3]}")
print("\n=== 3. Bo'sh turgan mijoz ===")
reader, writer = await asyncio.open_connection("127.0.0.1", port)
xabar = (await reader.readline()).decode().strip()
print(f" hech narsa yubormagan mijozga server: {xabar!r}")
print(f" keyin ulanish yopildi: {await reader.read() == b''}")
writer.close()
await writer.wait_closed()
print("\n=== 4. Boshqa jarayondan mijoz ===")
jarayon = await asyncio.create_subprocess_exec(
sys.executable, "-c", TASHQI_MIJOZ, str(port),
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
)
chiqish, _ = await asyncio.wait_for(jarayon.communicate(), timeout=20)
print(f" tashqi jarayon javoblari: {chiqish.decode().split()}")
print(f" chiqish kodi: {jarayon.returncode}")
print("\n=== 5. Statistika ===")
print(f" ulanishlar: {kv.statistika['ulanishlar']}")
print(f" buyruqlar: {kv.statistika['buyruqlar']}")
print(f" muddat bo'yicha uzilgan: {kv.statistika['muddat']}")
print(f" ⭐ bitta ip, bitta loop — {kv.statistika['ulanishlar']} ta ulanish (1 + 50 + 1 + 1 + 1)")
if __name__ == "__main__":
asyncio.run(main())Natijaning muhim qismi:
=== 1. Bitta mijoz ===
OK
python
YO'Q
OK
YO'Q
XATO noma'lum buyruq: SALOM
=== 2. 50 ta mijoz bir vaqtda ===
hamma SET javobi OK: True
hamma GET o'z qiymatini oldi: True
ombordagi kalitlar: 50, birinchilari: ['k00', 'k01', 'k02']
=== 3. Bo'sh turgan mijoz ===
hech narsa yubormagan mijozga server: 'XAYR muddat tugadi'
keyin ulanish yopildi: True
=== 4. Boshqa jarayondan mijoz ===
tashqi jarayon javoblari: ['OK', 'jarayon']
chiqish kodi: 0
=== 5. Statistika ===
ulanishlar: 54
buyruqlar: 109
muddat bo'yicha uzilgan: 1
⭐ bitta ip, bitta loop — 54 ta ulanish (1 + 50 + 1 + 1 + 1)Nima ko'rsatdi: 2.5, 2.6, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "asyncio'da poyga holati yo'q" | await orasida bor |
"asyncio.Queue iplar orasida ishlaydi" |
Faqat bitta loop ichida |
"writer.write ma'lumotni yuboradi" |
Buferga yozadi; drain kerak |
"Asinxron generator break da darhol tozalanadi" |
Kafolat — aclosing bilan |
"threading.Lock asinxron kodda ham ishlaydi" |
Loopni bloklaydi |
"Event.set() bitta vazifani uyg'otadi" |
Hammasini |
"readline() ulanish yopilsa xato beradi" |
b"" qaytaradi |
"Queue.join() ishchilarni to'xtatadi" |
Faqat task_done larni kutadi |
6. Keng tarqalgan xatolar va yechimlari
1. O'qish → await → yozish
balans = hisob.balans
await saqla()
hisob.balans = balans + summa # ❌
async with hisob.qulf: ... # ✅2. drain unutilgan
writer.write(katta_malumot) # ⚠️ bufer cheksiz o'sadi
await writer.drain() # ✅3. task_done unutilgan
x = await navbat.get()
ishla(x) # ❌ join abadiy kutadi
try: ... finally: navbat.task_done() # ✅4. Chegarasiz navbat
asyncio.Queue() # ⚠️ ishlab chiqaruvchi tez bo'lsa xotira to'ladi
asyncio.Queue(maxsize=1000) # ✅5. threading.Lock asinxron kodda
with threading.Lock(): await ... # ❌ loop bloklanadi
async with asyncio.Lock(): ... # ✅6. Qulf ichida uzoq kutish
async with qulf:
await tarmoq_sorovi() # ⚠️ hamma kutib qoladi7. Ulanishni yopmaslik
reader, writer = await asyncio.open_connection(...)
# ... writer.close() yo'q # ❌ resurs sizishi8. Mijozga muddat bermaslik
await reader.readline() # ⚠️ mijoz jim tursa — abadiy
async with asyncio.timeout(30): ... # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 9-qism (o'tilgan): iterator va generator protokollari
- 10-qism (o'tilgan): kontekst menejerlar
- 14.3-dars (o'tilgan): iplardagi poyga va
queue.Queue - 14.6-dars (o'tilgan): hodisa sikli
- 14.8-dars: modelni tanlash
- 20.1-dars: HTTP qanday ishlaydi — tarmoq ustidagi protokol
- 20-qism: FastAPI — asinxron endpointlar, fon vazifalari
- 23-qism: asinxron bazalar (
asyncpg, SQLAlchemy async)
8. Eng yaxshi amaliyotlar
Har
awaitni navbat almashish nuqtasi deb o'qing.Umumiy holat o'zgarishi
awaitni kesib o'tsa —asyncio.Lock.Qulf ichida tarmoq so'rovi qilmang — qulfni qisqa ushlang.
Navbatlarga
maxsizebering.task_donenifinallyda chaqiring.writedan keyindrain,closedan keyinwait_closed.Har bir o'qishga muddat bering.
Asinxron generatorlar —
aclosingbilan.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
import asyncio, contextlib
1. async def g():
yield 1
yield 2
async def m(): return [x async for x in g()]
print(asyncio.run(m()))
2. async def g():
yield 1
print(type(g()).__name__)
3. async def g():
yield 1
async def m():
it = g()
await anext(it)
return await anext(it, "tugadi")
print(asyncio.run(m()))
4. async def m():
q = asyncio.Queue()
await q.put(1); await q.put(2)
return await q.get(), q.qsize()
print(asyncio.run(m()))
5. async def m():
q = asyncio.LifoQueue()
for i in range(3): await q.put(i)
return await q.get()
print(asyncio.run(m()))
6. async def m():
q = asyncio.Queue(maxsize=1)
await q.put(1)
return q.full()
print(asyncio.run(m()))
7. async def m():
e = asyncio.Event()
a = e.is_set(); e.set()
return a, e.is_set()
print(asyncio.run(m()))
8. async def m():
l = asyncio.Lock()
async with l:
return l.locked()
print(asyncio.run(m()))
9. async def m():
s = asyncio.Semaphore(2)
async with s:
return s.locked()
print(asyncio.run(m()))
10. @contextlib.asynccontextmanager
async def r():
yield "ok"
async def m():
async with r() as x:
return x
print(asyncio.run(m()))
11. async def m():
q = asyncio.PriorityQueue()
for x in [(2, "b"), (1, "a")]: await q.put(x)
return (await q.get())[1]
print(asyncio.run(m()))
12. async def m():
h = 0
async def f():
nonlocal h
for _ in range(100):
h += 1
await asyncio.gather(f(), f())
return h
print(asyncio.run(m()))Javoblar
[1, 2]async_generatortugadi—anextning sukut qiymati(1, 1)2True(False, True)TrueFalse— yana bitta joy boroka200—awaityo'q, poyga yo'q
Vazifa 2: Xatolarni tuzating
1. async def otkazma(hisob, summa):
balans = await hisob.ol()
await hisob.saqla(balans - summa)
2. async def ishchi(navbat):
while True:
x = await navbat.get()
await ishla(x)
3. async def yubor(writer, bloklar):
for blok in bloklar:
writer.write(blok)
4. qulf = threading.Lock()
async def yangila():
with qulf:
await saqla()
5. async def ishlovchi(reader, writer):
while satr := await reader.readline():
writer.write(javob(satr))Javoblar
1. async def otkazma(hisob, summa):
async with hisob.qulf: # asyncio.Lock
balans = await hisob.ol()
await hisob.saqla(balans - summa)
2. async def ishchi(navbat):
while True:
x = await navbat.get()
try:
await ishla(x)
finally:
navbat.task_done() # join ishlashi uchun
3. async def yubor(writer, bloklar):
for blok in bloklar:
writer.write(blok)
await writer.drain() # orqa bosim
4. qulf = asyncio.Lock()
async def yangila():
async with qulf:
await saqla()
5. async def ishlovchi(reader, writer):
try:
while True:
async with asyncio.timeout(30):
satr = await reader.readline()
if not satr:
break
writer.write(javob(satr))
await writer.drain()
finally:
writer.close()
await writer.wait_closed()Vazifa 3: Chat serveri
asyncio stream lari bilan chat serveri yozing:
- Har mijoz
NICK ismbilan kiradi - Yozilgan xabar boshqa barcha mijozlarga tarqatiladi
- Har mijoz uchun alohida
Queue(maxsize=100)— sekin mijoz boshqalarni to'xtatmasin - Navbati to'lgan mijoz uziladi
- 100 ta sun'iy mijoz bilan sinab, hamma xabar yetib borganini tekshiring
Vazifa 4: Asinxron veb-o'rgimchak
- Boshlang'ich URL lardan
asyncio.Queueorqali sahifalarni aylanib chiqing (sun'iy "tarmoq" funksiyasi bilan) - Bir vaqtda ko'pi bilan 10 so'rov (
Semaphore) - Ko'rilgan URL lar to'plami — takrorlanmasin
- Chuqurlik chegarasi
- Hamma ishchi bo'sh qolganda to'xtash (
join+ to'xtatish signali)
Vazifa 5: Tezlik cheklovchi (rate limiter)
TezlikChegarasi(soniyada=10) asinxron kontekst menejerini yozing:
- "Token paqiri" (token bucket) algoritmi
async with chegara:— token bo'lmasa kutadi- 100 ta vazifa bilan sinab, soniyasiga 10 tadan oshmasligini isbotlang
ConditionyokiEventasosida adolatli navbat qiling
Vazifa 6: Parallel buyruqlar ishga tushiruvchisi
- Buyruqlar ro'yxatini
create_subprocess_execbilan parallel bajaring - Bir vaqtda ko'pi bilan 4 ta
- Har buyruqqa muddat; oshsa —
kill() - Chiqishni satrma-satr, buyruq nomi bilan jonli chop eting
- Oxirida jadval: buyruq, kod, vaqt
Vazifa 7: O'ylash
Iplar bilan yozilgan kodda poyga holati istalgan ikki bayt-kod ko'rsatmasi orasida yuz berishi mumkin (14.3-dars). asyncio'da esa — faqat await da. Bu farq kodni tekshirish (code review), testlash va nosozlik izlashga qanday ta'sir qiladi? asyncio'ning bu afzalligini nima buzishi mumkin?
Javob
Qisqa javob: asyncio'da xavfli nuqtalar ko'rinadigan va aniq — faqat await, async for, async with. Bu kod tekshirish va nosozlik izlashni ancha osonlashtiradi, poygalarni esa takrorlanadigan qiladi. Lekin bu afzallikni iplar, to_thread, yashirin await li yordamchi funksiyalar va tashqi holat (baza, fayl) buzishi mumkin.
1. Kodni tekshirish
| Iplar | asyncio | |
|---|---|---|
| Xavfli nuqtalar | Har qatorda | Faqat await da |
| Tekshiruvchi nimaga qaraydi | Hamma umumiy holatga | await ni kesib o'tadigan o'qish/yozishga |
| Qoida | "Umumiy o'zgaruvchi — qulf" | "O'qish → await → yozish — qulf" |
Tekshiruvchi await lar orasidagi blokni atomar tranzaksiya deb o'qiy oladi.
2. Testlash va takrorlanuvchanlik
- Iplarda poyga natijasi har ishga tushirishda boshqacha (14.3-dars) — test ba'zan o'tadi, ba'zan yiqiladi
- asyncio'da rejalashtirish deterministik: bu darsdagi Misol 3 har safar aynan
1000beradi - Demak poygani testda qayta hosil qilish va tuzatilganini isbotlash mumkin
await asyncio.sleep(0)ni ataylab qo'yib, eng yomon navbatni taqlid qilish mumkin
3. Nosozlik izlash
- Stek izi (traceback) bitta ipda — tushunarli
asyncio.all_tasks()vatask.print_stack()bilan hamma vazifa holatini ko'rish mumkindebug=Truesekin callback larni ko'rsatadi
4. Afzallikni nima buzadi
| Buzuvchi | Nega |
|---|---|
asyncio.to_thread / run_in_executor |
Funksiya boshqa ipda — umumiy holatga tegsa, iplar poygasi qaytadi |
Yashirin await |
await yordamchi() ichida yana await — "atomar" deb o'ylangan blok atomar emas |
| Tashqi holat | Baza, fayl, kesh — boshqa jarayonlar ham o'zgartiradi; Lock yordam bermaydi |
| Bir nechta loop / jarayon | asyncio.Lock faqat bitta loop ichida himoya qiladi |
| Free-threading (3.13t+) | Loop va to_thread ishchilari haqiqiy parallel ishlaydi |
Callback lar (call_soon) |
Navbat tartibi o'zgarishi mumkin |
5. Amaliy qoidalar
awaitni ko'rganda: "bu yerda dunyo o'zgarishi mumkin" deb o'ylangto_threadga faqat o'z ma'lumotini oladigan sof funksiyalarni bering- Tashqi holat uchun — baza tranzaksiyalari, optimistik qulflash (versiya ustuni)
- Ko'p jarayonli xizmatlarda — taqsimlangan qulf (Redis, Postgres advisory lock — 29-qism)
6. Xulosa
- asyncio poygani yo'q qilmaydi — uni ko'rinadigan va takrorlanadigan qiladi
- Bu kod tekshirish, testlash va nosozlik izlashni osonlashtiradi
- Iplarga chiqish, yashirin
awaitva tashqi holat bu afzallikni buzadi - Qoida bitta:
awaitni kesib o'tadigan o'qish-yozish — himoya talab qiladi
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda asinxron dasturning asosiy g'ishtlarini amaliyotda qo'lladik.
Eng muhim uch fikr:
Asinxron protokollar sinxronlarning aynan nusxasi.
async for/__anext__/StopAsyncIteration— iteratsiya,async with/__aenter__/__aexit__— resurslar,@asynccontextmanager— qisqa kontekst menejerlar. Asinxron generatorni o'rtada tashlab ketsangiz, tozalashnicontextlib.aclosingkafolatlaydi.asyncio.Queue— quvurlarning asosi.put/get/task_done/joinishlab chiqaruvchi va iste'molchilarni bog'laydi,maxsizeesa orqa bosim beradi: tez ishlab chiqaruvchi sekin iste'molchini kutadi va xotira o'smaydi. Ishchilarni to'xtatish uchun alohida signal (masalan,None) kerak —joinularni to'xtatmaydi.Bitta ip poygadan himoya qilmaydi. O'qish →
await→ yozish ketma-ketligida boshqa vazifa holatni o'zgartirib ulguradi: misolda 5000 ta yozuvdan 4000 tasi yo'qoldi. Yechim —asyncio.Lock(threading.Lockemas). Afzalligi: xavfli joylar faqatawaitlarda va natija takrorlanadi. Tarmoqda esa stream lar:write→drain,close→wait_closedva har o'qishga muddat.
Keyingi darsda 14-qismni yakunlaymiz: iplar, jarayonlar, subinterpretatorlar va asyncio — qaysi vazifaga qaysi modelni tanlash kerak, o'lchovlar bilan.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!