Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. "Taxmin qilma, o'lcha"
- 2.2. timeit — mikro-o'lchov
- 2.3. Buyruq qatorida timeit
- 2.4. cProfile — butun dastur
- 2.5. Natijalarni talqin qilish
- 2.6. pstats — tahlil
- 2.7. Erta optimizatsiya
- 2.8. Optimizatsiya ish oqimi
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — timeit bilan taqqoslash
- Misol 2 — cProfile bilan hotspot topish
- Misol 3 — pstats bilan tahlil va tottime vs cumtime
- Misol 4 — Amaliy: sekin kodni tezlashtirish
- 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
18.7-dars: Profiling — cProfile va timeit
18-QISM — SIFAT VA VOSITALAR · 7-dars
1. Kirish va motivatsiya
Kod ishlaydi, lekin sekin. Uni tezlashtirish kerak — lekin qayerdan boshlash kerak? Ko'p dasturchi bu yerda katta xato qiladi: ular kodning qaysi qismi sekinligini taxmin qilib, o'sha yerni optimallashtirishga urinadi. Taxmin ko'pincha noto'g'ri — asosiy sekinlik butunlay boshqa joyda bo'ladi. Profiling (profillash) — kodning qaysi qismi qancha vaqt olishini o'lchaydigan usul. "Taxmin qilma, o'lcha" — optimizatsiyaning birinchi qoidasi.
Python ikki asosiy profiling vositasiga ega: timeit (kichik kod bo'lagini aniq o'lchash) va cProfile (butun dasturda vaqt qayerga ketishini topish).
Real vaziyat. Bir jamoa hisobotlar sekin yaratilayotganidan shikoyat oldi. Dasturchi "bu SQL so'rovlari sekin" deb taxmin qildi va bir hafta so'rovlarni optimallashtirdi — natija deyarli o'zgarmadi. Keyin u cProfile ishlatdi va haqiqiy sekinlikni topdi: kod har hisobot uchun bir xil sozlama faylini minglab marta qayta o'qirdi. Bu bir qatorlik xato edi, lekin vaqtning 90% ini yeb qo'yardi. Uni tuzatib, hisobot 50 barobar tezlashdi — SQL ga umuman tegmasdan. Taxmin bir hafta isrof qildi; o'lchov muammoni bir zumda ko'rsatdi.
Bu darsda kodni profillashni — sekinlikni taxmin emas, o'lchash bilan topishni o'rganamiz.
Bu darsda:
- "Taxmin qilma, o'lcha" tamoyili
-
timeit— kichik kod bo'lagini o'lchash -
cProfile— butun dasturni profillash pstats— natijalarni tahlil qilish- Natijalarni talqin qilish (
ncalls,tottime,cumtime) - Erta optimizatsiya — "barcha yovuzlik ildizi"
- Optimizatsiya ish oqimi
- Amaliy: sekin kodni tezlashtirish
ℹ
timeitvacProfile— standart kutubxonada. Misollarda vaqt o'lchovlari o'zgaruvchan bo'lgani uchun nisbiy taqqoslash va chaqiruvlar soni (deterministik) ko'rsatiladi.
2. Nazariya — chuqur tushuntirish
2.1. "Taxmin qilma, o'lcha"
Optimizatsiyaning birinchi qoidasi — o'lchash:
| Taxmin | O'lchov |
|---|---|
| "Bu qism sekin bo'lsa kerak" | Aniq raqam |
| Ko'pincha noto'g'ri | Haqiqiy sekinlikni topadi |
| Vaqt isrofi | Optimizatsiyani to'g'ri yo'naltiradi |
Dasturchilarning sekinlik haqidagi sezgisi ko'pincha yanglishadi — asosiy sekinlik kutilmagan joyda bo'ladi. Faqat o'lchov haqiqatni ko'rsatadi.
2.2. timeit — mikro-o'lchov
timeit kichik kod bo'lagini ko'p marta ishga tushirib, o'rtacha vaqtini o'lchaydi (bir martalik o'lchov ishonchsiz):
import timeit
vaqt = timeit.timeit(lambda: sum(range(1000)), number=10000)
# yoki ikki yondashuvni taqqoslash:
t1 = timeit.timeit("'-'.join(str(i) for i in range(100))", number=10000)
t2 = timeit.timeit("'-'.join([str(i) for i in range(100)])", number=10000)| Parametr | Ma'nosi |
|---|---|
stmt |
O'lchanadigan kod (satr yoki funksiya) |
number |
Necha marta takrorlash |
setup |
Bir marta bajarilodigan tayyorlash |
timeit ko'p takrorlash bilan tasodifiy shovqinni kamaytiradi — kichik kod bo'laklarini taqqoslash uchun ideal.
2.3. Buyruq qatorida timeit
python -m timeit "'-'.join(str(i) for i in range(100))"
python -m timeit -s "d = {'a': 1}" "d.get('a')"Tez tekshiruv uchun — kod yozmasdan, terminaldan.
2.4. cProfile — butun dastur
cProfile butun dasturni ishga tushirib, har funksiya qancha vaqt olganini va necha marta chaqirilganini yozadi:
import cProfile
cProfile.run("main()")
# yoki buyruq qatorida:
# python -m cProfile -s cumtime skript.pyNamunaviy chiqish:
ncalls tottime percall cumtime percall filename:lineno(function)
1000 0.500 0.001 0.800 0.001 hisob.py:10(sekin_funksiya)
50000 0.300 0.000 0.300 0.000 hisob.py:5(yordamchi) cProfile — sekinlikni topish vositasi: qaysi funksiya eng ko'p vaqt oladi va necha marta chaqiriladi.
2.5. Natijalarni talqin qilish
| Ustun | Ma'nosi |
|---|---|
ncalls |
Funksiya necha marta chaqirilgan |
tottime |
Funksiyaning o'zida sarflangan vaqt (ichki chaqiruvlarsiz) |
cumtime |
Jami vaqt (ichki chaqiruvlar bilan) |
percall |
Bir chaqiruvga vaqt |
tottime — funksiyaning o'zi sekin (optimallashtiring); cumtime — u chaqirgan narsalar sekin. ncalls juda katta bo'lsa — funksiya ortiqcha chaqirilyapti (masalan sikl ichida).
2.6. pstats — tahlil
import cProfile, pstats
pr = cProfile.Profile()
pr.enable()
main()
pr.disable()
stats = pstats.Stats(pr)
stats.sort_stats("cumtime") # jami vaqt bo'yicha saralash
stats.print_stats(10) # eng sekin 10 ta| Saralash | Foydasi |
|---|---|
cumtime |
Jami vaqt (yuqoridan boshlab) |
tottime |
O'z vaqti (bevosita sekin) |
ncalls |
Chaqiruvlar soni (ortiqcha chaqiruv) |
2.7. Erta optimizatsiya
Donald Knuth: "Erta optimizatsiya — barcha yovuzlik ildizi". Bu:
| Erta optimizatsiya | To'g'ri yondashuv |
|---|---|
| Yozayotib har qatorni optimallashtirish | Avval to'g'ri, o'qiladigan kod |
| Taxmin bilan tezlashtirish | Profillab, hotspot'ni topish |
| Arzimas qismni optimallashtirish | Faqat haqiqiy sekinlikni |
| O'qib bo'lmas "tez" kod | Toza kod, keyin zarur bo'lsa optimallashtirish |
Qoida: avval ishlaydigan, toza kod yozing; sekin bo'lsa, profillang; faqat hotspot'ni optimallashtiring. Kodning 90% i tezlikka ta'sir qilmaydi — 10% hotspot'ga e'tibor bering.
2.8. Optimizatsiya ish oqimi
1. To'g'ri, toza kod yoz
2. Sekinmi? → profilla (cProfile)
3. Hotspot'ni top (eng ko'p vaqt/chaqiruv)
4. Faqat o'shani optimallashtir
5. Qayta o'lcha (yaxshilandi mi?)
6. Testlar hali o'tadimi? (17-qism)Har optimizatsiyadan keyin qayta o'lchang — ba'zi "optimizatsiya" aslida sekinlashtiradi. Va testlar hali o'tishini tekshiring — tezlik uchun to'g'rilikni qurbon qilmang.
3. Tez ma'lumotnoma
import timeit, cProfile, pstats
# mikro-o'lchov
timeit.timeit(lambda: kod(), number=10000)
# butun dastur
cProfile.run("main()")
# tahlil
pr = cProfile.Profile(); pr.enable(); main(); pr.disable()
pstats.Stats(pr).sort_stats("cumtime").print_stats(10)python -m timeit "kod"
python -m cProfile -s cumtime skript.pyQoidalar
taxmin qilma, o'lcha
timeit — kichik kod (ko'p takrorlash)
cProfile — butun dastur (hotspot topish)
tottime — o'z vaqti; cumtime — jami; ncalls — chaqiruvlar
erta optimizatsiya — yovuzlik ildizi
profilla → hotspot → optimallashtir → qayta o'lcha4. Batafsil misollar
Vaqt o'lchovlari o'zgaruvchan bo'lgani uchun misollarda nisbiy taqqoslash va chaqiruvlar soni (deterministik) ko'rsatiladi.
Misol 1 — timeit bilan taqqoslash
"""timeit kichik kod bo'laklarini o'lchaydi; ikki yondashuvni taqqoslash (nisbiy); ko'p takrorlash shovqinni kamaytiradi; taxmin emas, o'lchov."""
import timeit
def main() -> None:
print("=== 1. Ikki yondashuvni taqqoslash ===")
# ro'yxat tushunchasi vs generator (join uchun)
t_gen = timeit.timeit("'-'.join(str(i) for i in range(100))", number=20000)
t_list = timeit.timeit("'-'.join([str(i) for i in range(100)])", number=20000)
print(f" ro'yxat tushunchasi generatordan tez (join uchun): {t_list < t_gen}")
print("\n=== 2. Satr birlashtirish usullari ===")
setup = "sonlar = list(range(1000))"
t_join = timeit.timeit("''.join(str(s) for s in sonlar)", setup=setup, number=5000)
t_plus = timeit.timeit("""
natija = ''
for s in sonlar:
natija += str(s)
""", setup=setup, number=5000)
print(f" join += dan tez: {t_join < t_plus}")
print("\n=== 3. Lug'at kirish usullari ===")
setup = "d = {i: i for i in range(1000)}"
t_in = timeit.timeit("500 in d", setup=setup, number=100000)
t_keys = timeit.timeit("500 in d.keys()", setup=setup, number=100000)
print(f" 'x in d' 'x in d.keys()' dan tez: {t_in < t_keys}")
print("\n=== 4. To'plam vs ro'yxatda qidirish ===")
setup_list = "kolleksiya = list(range(10000))"
setup_set = "kolleksiya = set(range(10000))"
t_list = timeit.timeit("9999 in kolleksiya", setup=setup_list, number=10000)
t_set = timeit.timeit("9999 in kolleksiya", setup=setup_set, number=10000)
print(f" set'da qidirish ro'yxatdan tez: {t_set < t_list}")
print(" ⭐ o'lchov sezgini tasdiqladi: set — O(1), ro'yxat — O(n)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ikki yondashuvni taqqoslash ===
ro'yxat tushunchasi generatordan tez (join uchun): True
=== 2. Satr birlashtirish usullari ===
join += dan tez: True
=== 3. Lug'at kirish usullari ===
'x in d' 'x in d.keys()' dan tez: True
=== 4. To'plam vs ro'yxatda qidirish ===
set'da qidirish ro'yxatdan tez: True
⭐ o'lchov sezgini tasdiqladi: set — O(1), ro'yxat — O(n)Nima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — cProfile bilan hotspot topish
"""cProfile har funksiya chaqiruvlar sonini va vaqtini yozadi; ncalls deterministik; ortiqcha chaqirilgan funksiyani (hotspot) topish."""
import cProfile
import pstats
def yordamchi(x):
return x * x
def sekin_funksiya(n):
# yordamchi ni ko'p marta chaqiradi
return sum(yordamchi(i) for i in range(n))
def ish():
natija = 0
for _ in range(50):
natija += sekin_funksiya(100)
return natija
def main() -> None:
pr = cProfile.Profile()
pr.enable()
ish()
pr.disable()
stats = pstats.Stats(pr)
print("=== 1. Funksiya chaqiruvlari soni (deterministik) ===")
chaqiruvlar = {}
for func, (cc, nc, tt, ct, callers) in stats.stats.items():
nom = func[2]
if nom in ("yordamchi", "sekin_funksiya", "ish"):
chaqiruvlar[nom] = nc
for nom in ("ish", "sekin_funksiya", "yordamchi"):
print(f" {nom:18} {chaqiruvlar[nom]:6} marta chaqirilgan")
print("\n=== 2. Talqin ===")
print(f" ish: 1 marta (kirish nuqtasi)")
print(f" sekin_funksiya: 50 marta (sikl ichida)")
print(f" yordamchi: 50 × 100 = 5000 marta (ENG KO'P — hotspot)")
print(" ⭐ yordamchi eng ko'p chaqirilyapti — optimizatsiya shu yerga")
print("\n=== 3. Jami chaqiruvlar ===")
jami = sum(nc for func, (cc, nc, tt, ct, callers) in stats.stats.items())
print(f" jami funksiya chaqiruvlari: {jami}")
print(" ⭐ ncalls — deterministik: har run bir xil (vaqt esa o'zgaradi)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Funksiya chaqiruvlari soni (deterministik) ===
ish 1 marta chaqirilgan
sekin_funksiya 50 marta chaqirilgan
yordamchi 5000 marta chaqirilgan
=== 2. Talqin ===
ish: 1 marta (kirish nuqtasi)
sekin_funksiya: 50 marta (sikl ichida)
yordamchi: 50 × 100 = 5000 marta (ENG KO'P — hotspot)
⭐ yordamchi eng ko'p chaqirilyapti — optimizatsiya shu yerga
=== 3. Jami chaqiruvlar ===
jami funksiya chaqiruvlari: 10152
⭐ ncalls — deterministik: har run bir xil (vaqt esa o'zgaradi)Nima ko'rsatdi: 2.4, 2.5-bo'limlar.
Misol 3 — pstats bilan tahlil va tottime vs cumtime
"""pstats natijalarni saralaydi va filtrlaydi; tottime (o'z vaqti) vs cumtime (jami); chaqiruvchi/chaqirilgan; deterministik chaqiruv sonlari."""
import cProfile
import pstats
def past_daraja(x):
return x + 1
def orta_daraja(n):
return sum(past_daraja(i) for i in range(n))
def yuqori_daraja():
jami = 0
for _ in range(20):
jami += orta_daraja(50)
return jami
def main() -> None:
pr = cProfile.Profile()
pr.enable()
yuqori_daraja()
pr.disable()
stats = pstats.Stats(pr)
print("=== 1. Chaqiruvlar iyerarxiyasi ===")
sonlar = {}
for func, (cc, nc, tt, ct, callers) in stats.stats.items():
nom = func[2]
if nom in ("yuqori_daraja", "orta_daraja", "past_daraja"):
sonlar[nom] = nc
for nom, kutilgan in [("yuqori_daraja", 1), ("orta_daraja", 20), ("past_daraja", 1000)]:
print(f" {nom:16} {sonlar[nom]:5} marta (kutilgan: {kutilgan})")
print("\n=== 2. tottime vs cumtime tushunchasi ===")
print(" yuqori_daraja: tottime kichik (o'zi kam ish), cumtime katta (hammani chaqiradi)")
print(" past_daraja: tottime = cumtime (ichki chaqiruv yo'q, o'zi ishlaydi)")
print(" ⭐ tottime katta → funksiya O'ZI sekin; cumtime katta → chaqirganlari sekin")
print("\n=== 3. Chaqiruvchilar (callers) ===")
for func, (cc, nc, tt, ct, callers) in stats.stats.items():
if func[2] == "past_daraja":
chaqiruvchilar = [f[2] for f in callers]
print(f" past_daraja ni chaqirgan: {chaqiruvchilar}")
print("\n=== 4. Saralash (deterministik tekshiruv) ===")
# ncalls bo'yicha eng ko'p chaqirilgan (past_daraja)
eng_kop = max(
((func[2], nc) for func, (cc, nc, tt, ct, callers) in stats.stats.items()
if func[2] in ("yuqori_daraja", "orta_daraja", "past_daraja")),
key=lambda x: x[1])
print(f" eng ko'p chaqirilgan: {eng_kop[0]} ({eng_kop[1]} marta)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Chaqiruvlar iyerarxiyasi ===
yuqori_daraja 1 marta (kutilgan: 1)
orta_daraja 20 marta (kutilgan: 20)
past_daraja 1000 marta (kutilgan: 1000)
=== 2. tottime vs cumtime tushunchasi ===
yuqori_daraja: tottime kichik (o'zi kam ish), cumtime katta (hammani chaqiradi)
past_daraja: tottime = cumtime (ichki chaqiruv yo'q, o'zi ishlaydi)
⭐ tottime katta → funksiya O'ZI sekin; cumtime katta → chaqirganlari sekin
=== 3. Chaqiruvchilar (callers) ===
past_daraja ni chaqirgan: ['<genexpr>']
=== 4. Saralash (deterministik tekshiruv) ===
eng ko'p chaqirilgan: past_daraja (1000 marta)Nima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: sekin kodni tezlashtirish
Real optimizatsiya ish oqimini ko'rsatamiz: sekin funksiyani profillaymiz, hotspot'ni (ortiqcha ish) topamiz, optimallashtirib qayta o'lchaymiz va natijaning to'g'riligini tekshiramiz. Bu — "taxmin qilma, o'lcha, optimallashtir, qayta o'lcha" siklining namunasi.
"""optimizatsiya sikli: sekin kodni profillash, hotspot topish (takroriy hisob), keshlash bilan tezlashtirish, qayta o'lchash, to'g'rilikni tekshirish."""
import cProfile
import pstats
import timeit
from functools import lru_cache
# SEKIN: har chaqiruvda qaytadan hisoblaydi
def fib_sekin(n):
if n < 2:
return n
return fib_sekin(n - 1) + fib_sekin(n - 2)
# TEZ: keshlash bilan (10-dars, functools)
@lru_cache(maxsize=None)
def fib_tez(n):
if n < 2:
return n
return fib_tez(n - 1) + fib_tez(n - 2)
def main() -> None:
print("=== 1. Sekin versiyani profillash ===")
pr = cProfile.Profile()
pr.enable()
fib_sekin(25)
pr.disable()
stats = pstats.Stats(pr)
for func, (cc, nc, tt, ct, callers) in stats.stats.items():
if func[2] == "fib_sekin":
print(f" fib_sekin(25) uchun chaqiruvlar: {nc}")
print(" ⚠️ eksponensial — bir xil qiymat qayta-qayta hisoblanadi (hotspot)")
print("\n=== 2. Tez versiya (keshlash bilan) ===")
fib_tez.cache_clear()
pr = cProfile.Profile()
pr.enable()
fib_tez(25)
pr.disable()
stats = pstats.Stats(pr)
for func, (cc, nc, tt, ct, callers) in stats.stats.items():
if func[2] == "fib_tez":
print(f" fib_tez(25) uchun chaqiruvlar: {nc}")
print(" ⭐ har qiymat FAQAT BIR MARTA hisoblanadi (kesh)")
print("\n=== 3. Nisbiy tezlik o'lchovi ===")
fib_tez.cache_clear()
t_sekin = timeit.timeit(lambda: fib_sekin(25), number=5)
t_tez = timeit.timeit(lambda: fib_tez(25), number=5)
print(f" keshli versiya sekindan tezroq: {t_tez < t_sekin}")
print("\n=== 4. To'g'rilikni tekshirish (17-qism) ===")
fib_tez.cache_clear()
barcha_teng = all(fib_sekin(n) == fib_tez(n) for n in range(15))
print(f" ikki versiya bir xil natija beradi: {barcha_teng}")
print(" ⭐ optimizatsiya tezlashtirdi, LEKIN to'g'rilikni buzmadi")
print("\n=== 5. Xulosa ===")
print(" profilla (hotspot) → optimallashtir (kesh) → qayta o'lcha → testlar o'tadi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Sekin versiyani profillash ===
fib_sekin(25) uchun chaqiruvlar: 242785
⚠️ eksponensial — bir xil qiymat qayta-qayta hisoblanadi (hotspot)
=== 2. Tez versiya (keshlash bilan) ===
fib_tez(25) uchun chaqiruvlar: 26
⭐ har qiymat FAQAT BIR MARTA hisoblanadi (kesh)
=== 3. Nisbiy tezlik o'lchovi ===
keshli versiya sekindan tezroq: True
=== 4. To'g'rilikni tekshirish (17-qism) ===
ikki versiya bir xil natija beradi: True
⭐ optimizatsiya tezlashtirdi, LEKIN to'g'rilikni buzmadi
=== 5. Xulosa ===
profilla (hotspot) → optimallashtir (kesh) → qayta o'lcha → testlar o'tadiNima ko'rsatdi: 2.4, 2.7, 2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Sekinlikni sezaman" | Sezgi ko'pincha yanglishadi — o'lchang |
| "Har qatorni optimallashtirish kerak" | Faqat hotspot'ni (10%) |
| "Bir martalik o'lchov yetarli" | timeit — ko'p takrorlash |
"tottime va cumtime bir xil" |
tottime — o'z vaqti, cumtime — jami |
| "Optimizatsiya doim tezlashtiradi" | Ba'zan sekinlashtiradi — qayta o'lchang |
| "Erta optimizatsiya yaxshi" | "Barcha yovuzlik ildizi" — avval toza kod |
| "Tez kod = yaxshi kod" | To'g'rilik va o'qilishlik muhimroq |
| "cProfile vaqtni aniq beradi" | Vaqt o'zgaruvchan; chaqiruvlar deterministik |
6. Keng tarqalgan xatolar va yechimlari
1. Taxmin bilan optimallashtirish
# "bu sekin bo'lsa kerak" → optimallashtirish # ❌
cProfile.run("main()") # ✅ o'lchang2. Bir martalik time.time() o'lchovi
t = time.time(); kod(); print(time.time() - t) # ❌ shovqinli
timeit.timeit(lambda: kod(), number=10000) # ✅ ko'p takrorlash3. Arzimas qismni optimallashtirish
# kamdan-kam ishlaydigan kodni tezlashtirish # ❌
# ✅ hotspot (eng ko'p vaqt/chaqiruv) ga e'tibor4. Optimizatsiyadan keyin qayta o'lchamaslik
# "optimallashtirdim" (lekin tekshirmadim) # ❌
# ✅ profilla → optimallashtir → QAYTA profilla5. To'g'rilikni qurbon qilish
# tez, lekin noto'g'ri natija # ❌
# ✅ testlar hali o'tishini tekshiring (17-qism)6. Erta optimizatsiya
# yozayotib har qatorni tezlashtirish # ❌ o'qib bo'lmas kod
# ✅ avval toza kod, keyin (zarur bo'lsa) profilla7. ncalls ni e'tiborsiz qoldirish
# faqat vaqtga qarash # ncalls juda katta bo'lsa
# ✅ ortiqcha chaqiruvlar (sikl ichida) — hotspot belgisi7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 10-dars (o'tilgan):
functools.lru_cache— keshlash bilan optimizatsiya - 5-qism (o'tilgan): ma'lumot tuzilmalari — set vs list tezligi
- 11-qism (o'tilgan): xotira — vaqt va xotira muvozanati
- 17-qism (o'tilgan): testlar — optimizatsiyadan keyin to'g'rilikni tekshirish
- 29-qism: miqyoslash — profiling katta tizimlarda
8. Eng yaxshi amaliyotlar
Taxmin qilma, o'lcha —
cProfilebilan hotspot'ni toping.timeitbilan kichik kod bo'laklarini ko'p takrorlashda o'lchang.Faqat hotspot'ni (eng ko'p vaqt/chaqiruv) optimallashtiring.
Avval toza, to'g'ri kod; optimizatsiya keyin (zarur bo'lsa).
Har optimizatsiyadan keyin qayta o'lchang.
tottime(o'z vaqti) vacumtime(jami) farqini tushuning.ncallsjuda katta bo'lsa — ortiqcha chaqiruvni qidiring.Optimizatsiyadan keyin testlar (17-qism) hali o'tishini tekshiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # timeit number parametri nima uchun?
2. # cProfile ncalls nima?
3. # tottime va cumtime farqi?
4. # 'x in list' va 'x in set' qaysi tez?
5. # profiling birinchi qoidasi?
6. # ncalls juda katta nimani bildiradi?
7. # "erta optimizatsiya" haqida Knuth nima dedi?
8. # optimizatsiyadan keyin nima qilish kerak?
9. # python -m cProfile nima qiladi?
10. # timeit bir martalik o'lchovmi?
11. # kodning necha % i odatda hotspot?
12. # cumtime katta funksiya nima uchun sekin?Javoblar
- Ko'p takrorlab shovqinni kamaytirish
- Funksiya necha marta chaqirilgan
- tottime — o'z vaqti, cumtime — jami (ichki chaqiruvlar bilan)
x in set(O(1) vs O(n))- Taxmin qilma, o'lcha
- Funksiya ortiqcha chaqirilyapti (sikl ichida)
- "Erta optimizatsiya — barcha yovuzlik ildizi"
- Qayta o'lchash (yaxshilandimi) va testlar
- Skriptni profillaydi (buyruq qatorida)
- Yo'q — ko'p takrorlash
- ~10%
- U chaqirgan narsalar sekin (o'zi emas)
Vazifa 2: Xatolarni tuzating
1. import time
t = time.time()
natija = hisobla()
print(time.time() - t)
2. # "bu SQL sekin" deb taxmin qilib
# bir hafta SQL optimallashtirish
3. def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2) # sekin, lekin profilsiz
4. # optimallashtirdim (lekin qayta o'lchamadim)
5. # tez versiya yozdim (lekin test qilmadim)Javoblar
1. import timeit
vaqt = timeit.timeit(lambda: hisobla(), number=1000) # ko'p takror
2. cProfile.run("hisobot_yarat()") # avval profilla, hotspot'ni top
3. @lru_cache(maxsize=None) # profillab, keshlash qo'shildi
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
4. cProfile.run("main()") # optimizatsiyadan keyin qayta o'lcha
5. assert tez_versiya(n) == sekin_versiya(n) # to'g'rilikni tekshirVazifa 3: Benchmark to'plami
Turli yondashuvlarni timeit bilan taqqoslang:
- Ro'yxat tushunchasi vs
mapvs sikl str.joinvs+=satr birlashtirishdictvslistda qidirish- Natijalarni jadval qilib chiqaring (nisbiy)
Vazifa 4: Profillash mashqi
Sekin funksiyani profillang:
cProfilebilan hotspot'ni topingncalls,tottime,cumtimeni tahlil qiling- Ortiqcha chaqiruvni aniqlang
- Optimallashtirib qayta profillang
Vazifa 5: Optimizatsiya sikli
Ma'lum sekin kod uchun:
- Profillang, hotspot'ni yozing
- Uch xil optimizatsiya sinang
- Har biridan keyin qayta o'lchang
- Testlar hali o'tishini tasdiqlang
Vazifa 6: line_profiler
line_profiler (tashqi) bilan:
- Funksiyani qator-baqator profillang
- Eng sekin qatorni toping (
cProfilefunksiya darajasida) cProfilebilan solishtiring- Qachon qaysi biri foydali — yozing
Vazifa 7: O'ylash
Donald Knuth ning "erta optimizatsiya — barcha yovuzlik ildizi" iqtibosi ko'pincha noto'g'ri tushuniladi — u optimizatsiyaga qarshi emas, bevaqt optimizatsiyaga qarshi edi. To'liq iqtibos: "kichik samaradorlikni 97% vaqtda unutishimiz kerak: erta optimizatsiya — barcha yovuzlik ildizi. Lekin qolgan muhim 3% da imkoniyatni qo'ldan bermasligimiz kerak". Nima uchun optimizatsiya vaqti muhim, va "qachon optimallashtirish" savoli "qanday optimallashtirish" dan muhimroqmi?
Javob
Qisqa javob: Optimizatsiya vaqti muhim, chunki bevaqt optimizatsiya ikki narsani buzadi: kod o'qilishligini (tez lekin murakkab) va dasturchi vaqtini (arzimas qismga sarflangan). Knuth'ning asosiy fikri — optimizatsiya maqsadli bo'lishi kerak: avval to'g'ri, toza kod, keyin o'lchov bilan haqiqiy muhim 3% ni topib, faqat o'shani optimallashtirish. "Qachon" savoli "qanday" dan muhimroq, chunki noto'g'ri vaqtda (yoki noto'g'ri joyda) qilingan eng yaxshi optimizatsiya ham foydasiz.
1. Nega bevaqt optimizatsiya zararli
| Zarar | Tafsilot |
|---|---|
| O'qilishlik | Tez kod ko'pincha murakkab |
| Vaqt isrofi | Arzimas qismga sarflangan |
| Xatolar | Murakkab kod — ko'proq xato |
| Noto'g'ri joy | Sezgi yanglishadi |
| Erta qaror | Talab hali aniq emas |
2. Knuth'ning to'liq fikri
Iqtibos optimizatsiyaga qarshi emas — bevaqt ga qarshi:
- 97% vaqt: kichik samaradorlikni unuting (toza kod)
- 3% muhim: imkoniyatni qo'ldan bermang (o'lchab optimallashtiring)
3. "Qachon" > "qanday"
| Savol | Nega muhim |
|---|---|
| Qachon optimallashtirish | To'g'ri vaqt — muammo mavjud va o'lchangan |
| Qayerda | Hotspot — o'lchov ko'rsatadi |
| Qanday | Faqat qachon/qayerda aniq bo'lgach |
Eng yaxshi optimizatsiya noto'g'ri joyda foydasiz.
4. To'g'ri tartib
- To'g'ri, toza, o'qiladigan kod
- Ishlaydimi? (testlar)
- Sekinmi? (o'lchov)
- Qayerda? (profiling)
- Faqat o'shani optimallashtir
- Qayta o'lcha
5. Muhandislik saboqlari
- Optimizatsiya — o'lchovga asoslangan, maqsadli
- O'qilishlik va to'g'rilik — birinchi
- "Qachon/qayerda" — "qanday" dan oldin
- Ko'p kod tezlikka ta'sir qilmaydi (97%)
6. Xulosa
- Bevaqt optimizatsiya o'qilishlik va vaqtni buzadi
- Knuth maqsadli optimizatsiyani qo'llab-quvvatlaydi
- "Qachon/qayerda" — o'lchov bilan aniqlanadi
- Toza kod → o'lchov → maqsadli optimizatsiya
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda kodni profillashni — sekinlikni o'lchash bilan topishni o'rgandik.
Eng muhim uch fikr:
"Taxmin qilma, o'lcha." Optimizatsiyaning birinchi qoidasi — kodning qaysi qismi sekinligini taxmin qilmaslik, balki o'lchash. Dasturchilarning sezgisi ko'pincha yanglishadi — asosiy sekinlik kutilmagan joyda bo'ladi.
timeitkichik kod bo'laklarini ko'p takrorlash bilan aniq o'lchaydi (bir martalik o'lchov shovqinli),cProfileesa butun dasturda vaqt qayerga ketishini va har funksiya necha marta chaqirilganini ko'rsatadi.cProfileva natijalarni talqin.cProfilehar funksiyaningncalls(chaqiruvlar soni — deterministik),tottime(o'z vaqti, ichki chaqiruvlarsiz) vacumtime(jami vaqt) ni beradi.tottimekatta — funksiya o'zi sekin;cumtimekatta — u chaqirgan narsalar sekin;ncallsjuda katta — funksiya ortiqcha (sikl ichida) chaqirilyapti.pstatsbilan natijalarni saralab, filtrlab, hotspot'ni topasiz.Erta optimizatsiya — "barcha yovuzlik ildizi". Avval to'g'ri, toza, o'qiladigan kod yozing; sekin bo'lsa, profillang; faqat hotspot'ni (kodning ~10% i) optimallashtiring. Ish oqimi: profilla → hotspot → optimallashtir → qayta o'lcha (ba'zi "optimizatsiya" aslida sekinlashtiradi) → testlar hali o'tadimi (tezlik uchun to'g'rilikni qurbon qilmang). Knuth'ning fikri — optimizatsiyaga qarshi emas, bevaqt optimizatsiyaga qarshi.
Keyingi darsda — 18-qismning yakuniy darsi: debugging (pdb va IDE) — koddagi xatolarni print bilan emas, tuzatgich (debugger) bilan tizimli topish: to'xtash nuqtalari, qadam-baqadam ijro va o'zgaruvchilarni tekshirish.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!