Konkurentlik va parallelizm: farqi nimada
Asoslar4 daqInnovialabs tahririyati
Qisqacha
Konkurentlik — bir nechta vazifani ular orasida almashib olib borish qobiliyati; parallelizm esa bir nechta vazifaning turli yadrolarda aynan bir vaqtda bajarilishi.
Qisqa javob
Konkurentlik (concurrency) — dastur tuzilishiga oid tushuncha: dastur bir nechta vazifani ish holatida ushlab turadi va ulardan biri nimanidir kutayotganda boshqasiga o‘tadi.
Parallelizm (parallelism) — bajarilishga oid tushuncha: bir nechta vazifa protsessorning turli yadrolarida aynan bir paytda bajariladi.
Konkurent dastur bitta yadroda ishlashi mumkin. Parallel dasturga bir nechta yadro kerak. Ular bir-birini inkor etmaydi: yaxshi qurilgan tizim ko‘pincha ham konkurent, ham parallel bo‘ladi.
Oshxona misoli
Bitta oshpazni tasavvur qiling. U suvni olovga qo‘yadi, suv qaynaguncha sabzavot to‘g‘raydi, keyin sousni aralashtiradi. Har bir lahzada u faqat bitta ish qiladi, lekin uchta taom ham oldinga siljiydi. Bu — konkurentlik.
Endi oshxonada uchta oshpaz bor va har biri o‘z taomini tayyorlaydi. Ish aynan bir vaqtda ketadi. Bu — parallelizm.
Asosiy xulosa: agar oshpaz asosan kutsa (suv qaynayapti, duxovka pishiryapti), ikkinchi oshpaz deyarli yordam bermaydi — to‘g‘ri almashib turish kifoya. Agar oshpazning qo‘li doim band bo‘lsa (tog‘dek sabzavot to‘g‘rash), faqat yana bir juft qo‘l yordam beradi.
Ikki turdagi yuklama
Qaysi vositani tanlash yuklama turiga bog‘liq.
- I/O-bound — vazifa asosan kutadi: ma’lumotlar bazasi javobi, HTTP so‘rov, fayl o‘qish, navbatdan xabar. Bu vaqtda protsessor bo‘sh turadi.
- CPU-bound — vazifa asosan hisoblaydi: rasmlarga ishlov berish, siqish, shifrlash, hisob-kitoblar, modellarni o‘qitish.
I/O-bound yuklama uchun konkurentlik kerak. CPU-bound uchun — parallelizm.
Thread, process va async
| Mexanizm | Bu nima | Kuchli tomoni | Zaif tomoni |
|---|---|---|---|
| Process | O‘z xotirasiga ega alohida dasturlar | Haqiqiy parallelizm, izolyatsiya | Xotirani ko‘proq oladi, ma’lumot almashish murakkabroq |
| Thread | Bitta process ichidagi bir nechta bajarilish oqimi | Umumiy xotira, I/O kutish uchun qulay | Data race, bloklashlar kerak |
| Async I/O | Bitta event loop vazifalarni kutish nuqtalarida almashtiradi | Kam xarajat bilan minglab ulanishlar | Bloklovchi kod hammasini to‘xtatadi; async kutubxonalar kerak |
Async — sof konkurentlik: vazifalar await da boshqaruvni o‘zlari beradi, event loop esa keyingisini ishga tushiradi. Hech kim protsessorni uzoq band qilmasa, bu juda samarali.
Python dagi GIL nima
Standart CPython implementatsiyasida GIL (Global Interpreter Lock) bor — har bir lahzada faqat bitta thread ga Python bytecode ni bajarishga ruxsat beradigan global qulf.
Amalda bu nimani anglatadi:
- Python dagi thread lar I/O-bound vazifalar uchun yaxshi: tarmoq yoki diskni kutayotganda GIL bo‘shatiladi va boshqa thread lar ishlaydi.
- Thread lar sof Python dagi CPU-bound kodni tezlashtirmaydi: hisoblashlar baribir navbat bilan ketadi.
- Parallel hisoblash uchun process lar (
multiprocessing,ProcessPoolExecutor) yoki og‘ir ishni GIL dan tashqarida bajaradigan kutubxonalar (masalan, NumPy ning ko‘p funksiyalari) ishlatiladi.
Python ning yangi versiyalarida GIL siz eksperimental yig‘ma paydo bo‘ldi, lekin ko‘pchilik loyihalarda hozircha GIL bor deb hisoblagan ma’qul.
import asyncio
from concurrent.futures import ProcessPoolExecutor
async def fetch_all(client, urls):
# I/O-bound: async orqali konkurentlik
return await asyncio.gather(*(client.get(u) for u in urls))
def heavy(n):
return sum(i * i for i in range(n))
def compute_all(numbers):
# CPU-bound: process lar orqali parallelizm
with ProcessPoolExecutor() as pool:
return list(pool.map(heavy, numbers))
Yondashuvni qanday tanlash
- Vazifa nimani kutishini aniqlang. Agar tarmoq yoki diskni — async yoki thread lardan boshlang.
- Ko‘p ulanishlar va zamonaviy stek (FastAPI, aiohttp, aiogram) — async.
- Eski sinxron kutubxonalar va o‘rtacha yuklama — thread pool.
- Og‘ir hisoblashlar — process pool yoki ishni alohida servis yoki vazifalar navbatiga chiqarish.
- Aralash yuklama — I/O uchun async, og‘ir qismlarni esa
run_in_executororqali process pool ga bering.
Ko‘p uchraydigan xatolar
- Async kod ichida bloklovchi chaqiruv.
time.sleepyoki sinxron ma’lumotlar bazasi drayveri butun event loop ni muzlatib qo‘yadi. - Python dagi hisob-kitoblar uchun thread lar tezlashuv umidida — GIL tufayli tezlashuv bo‘lmaydi.
- Juda ko‘p process. Yadrolardan ko‘p process odatda faqat qo‘shimcha xarajat qo‘shadi.
- Himoyasiz umumiy o‘zgaruvchan ma’lumotlar. Race holatlari kam va kutilmaganda chiqadi, shuning uchun ularni tuzatish qiyin.