# Производителност на Python: собствени цикли на NumPy, обратни извиквания и разходи за преобразуване

Published: 2026-10-17

Контролиран числен тест само с процесор проследява идентични стойности чрез цикли на CPython, аритметика на NumPy, обвивка за обратно извикване на Python и компилиран цикъл на Numba. NumPy с готов вход имаше голяма преднина, докато преобразуването от и обратно към списъци на Python намали това предимство до почти равенство. Епизодът обяснява границата на изпълнение и как да се измери резултатът, от който се нуждае едно приложение.

Canonical: https://thedailydiff.dev/bg/video/2026-10-17-python-native-loops/

## Какво обхваща този видеоклип

- CPython компилира изходния код до байткод. Повтарящата се работа на интерпретатора/обекта и типизиран собствен числен цикъл са различни организации на изпълнение.
- Числената аритметика на NumPy може да предава типизирани пакети на компилирани операции; аритметичният цикъл все още съществува и изгледите могат да имат несъседни оформления.
- Измерете преобразуването и необходимата изходна репрезентация. В това изпълнение преобразуването на списъци на Python в масиви и обратно изтри голямата преднина на готовия масив.
- Малките натоварвания могат да предпочитат обикновен Python, защото фиксираните разходи за извикване на масив са от значение. Разбирането на осем стойности спечели това измерено сравнение.
- np.vectorize е удобна обвивка, която извиква Python за последователни елементи; самият пакетен интерфейс не установява собствено числено изпълнение.
- Компилираните цикли със синтаксис на Python също могат да бъдат бързи. Включете разходите за студена компилация/настройка, когато те са от значение за извикващия.
- Собственото изпълнение, CPU SIMD, многонишковостта и GPU бекендите са отделни идеи. Наличните функции на процесора не проследяват използваните инструкции в конкретно изпълнение.

## Глави

- 0:00 Защо един и същ процесор може да завърши по-рано?
- 0:52 Каква работа повтаря цикълът на Python?
- 1:38 Къде NumPy премества цикъла?
- 2:13 Означава ли бързо GPU или много ядра на процесора?
- 2:49 Кога впечатляващото ускорение изчезва?
- 3:28 Кои граници принадлежат на бенчмарка?
- 4:00 Може ли компилиран цикъл на Python също да бъде бърз?
- 4:56 Какво всъщност изпълнява np.vectorize?
- 5:41 Какво трябва да промените в кода си?

## Преведен препис

Преведено от оригиналния английски разказ. Наличните аудио и субтитри се контролират от YouTube.

### Защо един и същ процесор може да завърши по-рано?

0:00 Смятате, че Python се нуждае от нов език, за да стане бърз. Същият процесор изпълни нашата партида по-бързо, след като цикълът се премести. Къде отиде работата? Кога изчезва ускорението? Кой пряк път връща Python обратно? Това е The Daily Diff, под капака. Наблюдавайте този пряк път. CPython е стандартната реализация на Python.

0:17 Той компилира вашия изходен код в байткод, след което изпълнява тези инструкции в интерпретатор. NumPy е числова библиотека, чиито масиви съдържат стойности с деклариран тип данни. Вградената му аритметика може да предаде цяла партида на компилирани операции. Вземете един милион стойности с плаваща запетая, повдигнете всяка на квадрат, след това добавете оригиналната стойност. Всяка версия получава идентични стойности и произвежда съвпадащи отговори. Стойностите са достатъчно малки, за да не допускат разлики в закръгляването от състезанието.

0:40 На тази машина, разбирането отне около тридесет и три милисекунди. NumPy отне по-малко от една. И двете работеха на процесора. Това е полезно доказателство за това натоварване и ужасен некролог за език за програмиране. Започнете с обикновения цикъл.

### Каква работа повтаря цикълът на Python?

0:53 Python получава следващата стойност, извършва аритметиката и добавя отговора. След това го прави отново. Умножението е евтино. Организирането на следващото умножение и обработката на обектите на Python около него добавя работа всеки път. Това е действителната дезасемблиране на тестваната функция. Итерация, умножение и събиране се появяват като байткод инструкции. Версиите и интерпретаторите на Python правят различни избори.

1:14 Тези времена принадлежат на версията на екрана, която е Python 3.10. Списъкът на Python съхранява препратки към обекти, така че различни видове неща могат да споделят списък. Нашата аритметична задача използва числа навсякъде. Тя плаща за обща подредба, докато заявява повтаряща се услуга. Представете си, че поръчвате едно и също кафе милион пъти и попълвате нов формуляр за всяка чаша. Машината за кафе е наред.

1:36 Документацията е развила собствена кариера.

### Къде NumPy премества цикъла?

1:38 NumPy променя договора. Този масив съдържа стойности с плаваща запетая с фиксиран размер и един деклариран тип. Нашият масив е непрекъснат, така че стойностите му са разположени заедно в паметта. Изгледите могат да имат други оформления. Аритметичната операция знае какъв тип данни получава. Извикването предава пакета на собствена операция. Цикъл все още посещава стойностите вътре в компилирания код. Той може да използва повторно знанието за типа в тази работа.

2:00 Python остава човекът, който предава работата. Итамар Търнър Трауринг обяснява разликата в Python Speed. Пакетните интерфейси, собствените реализации и векторните инструкции на процесора са отделни неща. Името на функцията предоставя много малко доказателства.

### Означава ли бързо GPU или много ядра на процесора?

2:13 Този резултат използва NumPy на процесора. GPU бекенд като CuPy избира различно място за масиви и операции. Купуването на GPU оставя този обикновен цикъл на Python да работи там, където вече е работил. Векторните инструкции на процесора могат да обработват няколко стойности едновременно. NumPy има механизми за избор на поддържани ядра. Нашето време за изпълнение отчита наличните функции, но не проследява инструкциите на това изражение. Приписването на цялата измерена печалба на векторни инструкции би преувеличило доказателствата.

2:40 Количката за пазаруване на GPU може да остане затворена. Има нещо дълбоко удовлетворяващо в решение за производителност, което също отменя покупка. За съжаление, бенчмаркът продължава.

### Кога впечатляващото ускорение изчезва?

2:49 С осем стойности, разбирането спечели. Извикването на механизма на масива струваше повече от малката задача. По-големите готови масиви излязоха напред. Използвахме повтарящи се опити и загрят процес. По-новите версии на Python могат да променят пресичането. След това променете това, от което се нуждае приложението. Започнете със списък на Python и завършете с нов списък на Python. NumPy трябва да преобразува входа в масив и да превърне отговора обратно в обекти на Python.

3:11 Тези стъпки са част от сметката, ако вашето приложение се нуждае от тях. При милион стойности, този пълен път отне около двадесет и осем милисекунди. Разбирането също отне около двадесет и осем. Нашата драматична преднина стана почти равенство. Бързата част беше реална. Предимството зависеше от запазването на данните в техния числов формат.

### Кои граници принадлежат на бенчмарка?

3:28 Следвайте данните. Ако следващата операция приема масив, запазете масива. Ако многократно преобразувате между списъци и масиви, измерете тези пресичания. Спирането преди скъпо предаване дава точни числа за грешния въпрос. Умножаването на този масив създава временен резултат. Добавянето на оригиналните стойности създава изхода. Нативното изпълнение все още се нуждае от памет и премества данни.

3:47 Някои операции приемат изходен буфер, намалявайки разпределенията, когато вашият код може безопасно да го използва повторно. Един хубав ред може да поръча няколко големи буфера. Python Speed също посочва този проблем. Разпределителят е изключително безразличен към вашата естетика.

### Може ли компилиран цикъл на Python също да бъде бърз?

4:00 Можете също така да запазите синтаксиса на цикъла и да промените неговото изпълнение. Numba може да компилира поддържани числови функции на Python в собствен код. Ето цикъла от нашия тест с неговия декоратор за компилатор. Все още пише „за“. Скъпият път на интерпретатора е променен. След компилация, този цикъл отне по-малко от половин милисекунда с готови масиви. Самата компилация отне около секунда в това изпълнение. Тази цена за настройка беше изключена от повтарящите се измервания на времето,

4:22 така че малка еднократна задача заслужава различно сравнение. Собственото ръководство на Numba е щастливо да покаже изрични цикли. Започването на миграция на език, преди да се намери горещият път, е сложен начин да се избегне отварянето на профайлър. Първо намерете какво консумира времето. Мрежови изчаквания, анализ на обекти и групова аритметика изискват различни корекции. Нативните операции с масиви помагат, когато изчислението и данните съвпадат.

4:43 Измерете резултата, от който извикващият наистина се нуждае. Сега за този пряк път. Имате функция на Python и искате тя да приема масив. Обвивка с име vectorize звучи като липсващия бутон за производителност. Нейната документация съдържа важно изречение, което чака.

### Какво всъщност изпълнява np.vectorize?

4:56 NumPy казва, че обвивката vectorize е предоставена предимно за удобство. Неговата реализация е по същество цикъл for. Обвивката приема пакети, но продължава да извиква вашата функция на Python за последователни елементи. Интерфейсът стана по-къс. Границата на изпълнение остана заета. Гледайте как същите стойности се връщат чрез обратното извикване на Python. С готови масиви, тази версия отне около осемдесет и седем милисекунди. Беше по-бавна от нашето разбиране.

5:18 Полезна обвивка за излъчване може да запази точната работа за всеки елемент, която сте се опитвали да премахнете. Проверете реализацията зад пакетен интерфейс, съхранявайте съвместими данни в тяхната полезна форма и включете преобразуването в сравнението. Нативните, обратни извиквания и компилирани цикли могат да изглеждат сходни от позицията на извикващия. Името vectorize направи обещание, което вашият хронометър никога не е подписал. Запазете го, когато удобството е това, от което се нуждаете. За производителност, проверете цикъла, който се изпълнява.

### Какво трябва да промените в кода си?

5:41 Моята присъда е SHIP IT за пакетна обработка на измерен числен горещ път. Запазете обикновените цикли, когато вече работят добре. Проверете къде се извършва работата и от какво се нуждае следващият извикващ. Абонирайте се, натиснете камбанката и ми кажете в коментарите дали бихте го подпечатали по различен начин. И това е разликата за днес. Аз съм Нико от Axrisi. Сливайте отговорно.

## Източници

- [Universal functions (ufunc) basics — NumPy 2.2](https://numpy.org/doc/2.2/user/basics.ufuncs.html) — NumPy
- [The N-dimensional array — NumPy 2.2](https://numpy.org/doc/2.2/reference/arrays.ndarray.html) — NumPy
- [numpy.vectorize — convenience and performance notes](https://numpy.org/doc/2.2/reference/generated/numpy.vectorize.html) — NumPy
- [CPU/SIMD optimizations — NumPy 2.2](https://numpy.org/doc/2.2/reference/simd/index.html) — NumPy
- [dis — Disassembler for Python bytecode](https://docs.python.org/3.10/library/dis.html) — Python Software Foundation
- [CPython 3.10.12 list representation](https://github.com/python/cpython/blob/v3.10.12/Include/cpython/listobject.h) — CPython contributors
- [The limits of Python vectorization as a performance technique](https://pythonspeed.com/articles/vectorization-python-alternatives/) — Itamar Turner-Trauring / Python⇒Speed
- [Performance Tips](https://numba.readthedocs.io/en/stable/user/performance-tips.html) — Numba
- [Basics of CuPy](https://docs.cupy.dev/en/stable/user_guide/basic.html) — CuPy
