+− THE DAILY DIFFdev & AI news
SHIP IT

Pagganap ng Python: mga native na loop ng NumPy, mga callback at mga gastos sa conversion

Ang isang kinokontrol na numerical test na CPU-only ay sumusunod sa magkaparehong halaga sa pamamagitan ng mga loop ng CPython, aritmetika ng NumPy, isang Python callback wrapper at isang compiled na Numba loop.

Want to see our stories first on Google? Add us to your preferred sources — it helps us grow.

Ang isang kinokontrol na numerical test na CPU-only ay sumusunod sa magkaparehong halaga sa pamamagitan ng mga loop ng CPython, aritmetika ng NumPy, isang Python callback wrapper at isang compiled na Numba loop. Ang ready-input na NumPy ay may malaking lamang, habang ang conversion mula at pabalik sa mga listahan ng Python ay nagpababa sa kalamangan na iyon sa halos tabla. Ipinaliwanag ng episode ang execution boundary at kung paano sukatin ang resulta na kailangan ng isang application.

Basahin ang nakasulat na edisyon (English) ↗

Ang sakop ng video na ito

  • Kinompila ng CPython ang source sa bytecode. Ang paulit-ulit na interpreter/object work at isang naka-type na native numeric loop ay iba't ibang arrangement ng execution.
  • Ang numeric na aritmetika ng NumPy ay maaaring magbigay ng mga naka-type na batch sa mga compiled na operasyon; umiiral pa rin ang arithmetic loop, at ang mga view ay maaaring magkaroon ng noncontiguous layouts.
  • Sukatin ang conversion at ang kinakailangang output representation. Sa pagpapatakbong ito, ang pag-convert ng mga listahan ng Python sa mga array at pabalik ay nagtanggal ng malaking lamang ng ready-array.
  • Ang maliliit na workload ay maaaring paboran ang ordinaryong Python dahil mahalaga ang mga nakapirming gastos sa array-call. Ang eight-value comprehension ang nanalo sa sinusukat na paghahambing na ito.
  • Ang np.vectorize ay isang convenience wrapper na tumatawag sa Python para sa sunud-sunod na elemento; ang isang batch interface lamang ay hindi nagtatatag ng native numerical execution.
  • Ang mga compiled na Python-syntax loops ay maaari ding maging mabilis. Isama ang cold compilation/setup costs kapag mahalaga ang mga ito sa tumatawag.
  • Ang native execution, CPU SIMD, multithreading at GPU backends ay magkahiwalay na ideya. Ang mga available na feature ng CPU ay hindi sumusubaybay sa mga instruction na ginamit sa isang partikular na pagpapatakbo.

Isinaling transcript

Isinalin mula sa orihinal na salaysay sa English. Ang available na audio at mga caption ay kinokontrol ng YouTube.

Bakit mas maaga makakatapos ang parehong CPU?

0:00 Sa tingin mo ay nangangailangan ng bagong wika ang Python para bumilis. Ang parehong CPU ay nagpatakbo ng aming batch nang mas mabilis matapos ilipat ang loop. Saan napunta ang trabaho? Kailan nawawala ang pagbilis? Aling shortcut ang nagbabalik sa Python? Ito ang The Daily Diff, sa ilalim ng hood. Pagmasdan ang shortcut na iyon. Ang CPython ay ang karaniwang implementasyon ng Python.

0:17 Kinompila nito ang iyong source sa bytecode, pagkatapos ay pinapatakbo ang mga instruction na iyon sa isang interpreter. Ang NumPy ay isang numerical library na ang mga array ay nagtataglay ng mga halaga na mayroong idineklarang uri ng data. Ang built in na aritmetika nito ay maaaring magbigay ng isang buong batch sa mga compiled na operasyon. Kumuha ng isang milyong floating point values, i-square ang bawat isa, pagkatapos ay idagdag ang orihinal na halaga. Ang bawat bersyon ay nakakakuha ng magkaparehong halaga at gumagawa ng magkatugmang mga sagot. Ang mga halaga ay sapat na maliit upang maiwasan ang mga pagkakaiba sa rounding sa labanan.

0:40 Sa makina na ito, ang comprehension ay umabot ng mga tatlumpu't tatlong millisecond. Ang NumPy ay umabot ng mas mababa sa isa. Pareho silang tumakbo sa CPU. Iyan ay kapaki-pakinabang na ebidensya para sa workload na ito, at isang kahila-hilakbot na obitwaryo para sa isang programming language. Magsimula sa ordinaryong loop.

Anong trabaho ang inuulit ng isang Python loop?

0:53 Kinukuha ng Python ang susunod na halaga, ginagawa ang aritmetika, at idinurugtong ang sagot. Pagkatapos ay ginagawa itong muli. Mura ang pagpaparami. Ang pag-aayos ng susunod na pagpaparami, at paghawak sa mga Python object sa paligid nito, nagdaragdag ng trabaho bawat oras. Ito ang aktwal na disassembly ng nasubok na function. Ang pag-ulit, pagpaparami at pagdaragdag ay lumalabas bilang mga instruction ng bytecode. Iba't ibang pagpipilian ang ginagawa ng mga bersyon at interpreter ng Python.

1:14 Ang mga timing na ito ay nauugnay sa bersyon na ipinapakita sa screen, na Python 3.10. Ang isang listahan ng Python ay nag-iimbak ng mga reference sa mga object, kaya't iba't ibang uri ng bagay ang maaaring magbahagi ng isang listahan. Ang aming gawain sa aritmetika ay gumagamit ng mga numero sa kabuuan. Nagbabayad ito para sa isang pangkalahatang arrangement habang humihingi ng paulit-ulit na serbisyo. Isipin mo na nag-oorder ka ng parehong kape ng isang milyong beses at pumupuno ng bagong form para sa bawat tasa. Ayos lang ang coffee machine.

1:36 Ang mga papeles ay nagkaroon na ng sarili nitong karera.

Saan inililipat ng NumPy ang loop?

1:38 Binabago ng NumPy ang kontrata. Ang array na ito ay naglalaman ng mga fixed size na floating point values na may isang idineklarang uri. Ang aming array ay contiguous, kaya magkakasama ang mga halaga nito sa memory. Ang mga view ay maaaring magkaroon ng ibang mga layout. Alam ng arithmetic operation kung anong uri ng data ang tinatanggap nito. Ibinibigay ng tawag ang batch sa isang native operation. Mayroon pa ring loop na dumadalaw sa mga halaga sa loob ng compiled code. Maaari nitong gamitin muli ang kaalaman sa uri sa buong trabaho na iyon.

2:00 Ang Python ay nananatiling tao na nagbibigay ng trabaho. Ipinaliwanag ni Itamar Turner Trauring ang pagkakaiba sa Python Speed. Ang mga batch interface, native implementation at processor vector instruction ay magkahiwalay na bagay. Maliit na ebidensya lamang ang ibinibigay ng pangalan ng function.

Mabilis ba ang ibig sabihin ay GPU o maraming CPU cores?

2:13 Ang resultang ito ay gumamit ng NumPy sa CPU. Ang isang GPU backend tulad ng CuPy ay pumipili ng ibang tahanan para sa mga array at operasyon. Ang pagbili ng GPU ay iniiwan ang ordinaryong Python loop na ito na tumatakbo kung saan ito tumatakbo na. Ang mga instruction ng vector ng CPU ay maaaring magproseso ng ilang halaga nang magkasama. May makinarya ang NumPy para sa pagpili ng mga sinusuportahang kernel. Ang aming runtime ay nag-uulat ng mga magagamit na feature, ngunit hindi sinusubaybayan ang mga instruction ng expression na ito. Ang pagbibigay ng buong nakuha na pakinabang sa mga vector instruction ay magpapababa sa ebidensya.

2:40 Maaaring manatiling sarado ang shopping cart ng GPU. Mayroong isang bagay na lubos na nagbibigay-kasiyahan tungkol sa pag-aayos ng pagganap na nagkakansela rin ng pagbili. Sa kasamaang palad, nagpapatuloy ang benchmark.

Kailan nawawala ang kahanga-hangang pagbilis?

2:49 Sa walong halaga, ang comprehension ang nanalo. Mas malaki ang gastos ng pagtawag sa makinarya ng array kaysa sa maliit na trabaho. Ang mas malalaking ready arrays ang nanguna. Gumamit kami ng paulit-ulit na pagsubok at isang warmed na proseso. Maaaring baguhin ng mga mas bagong build ng Python ang crossover. Pagkatapos ay baguhin kung ano ang kailangan ng application. Magsimula sa isang listahan ng Python at tapusin sa isang bagong listahan ng Python. Dapat i-convert ng NumPy ang input sa isang array at ibalik ang sagot sa mga Python

3:11 object. Ang mga hakbang na iyon ay kabilang sa bayarin kung kailangan ng iyong application ang mga ito. Sa isang milyong halaga, ang kumpletong path na iyon ay umabot ng mga dalawampu't walong millisecond. Ang comprehension ay umabot din ng mga dalawampu't walong. Ang aming dramatikong lamang ay naging halos tabla. Totoo ang mabilis na bahagi. Ang kalamangan ay nakasalalay sa pagpayag na manatili ang data sa numerical form nito.

Aling mga boundary ang kabilang sa benchmark?

3:28 Sundin ang data. Kung ang susunod na operasyon ay tumatanggap ng array, panatilihin ang array. Kung paulit-ulit kang nagko-convert sa pagitan ng mga listahan at array, sukatin ang mga pagtawid na iyon. Ang paghinto bago ang isang magastos na handoff ay nagbibigay ng tumpak na numero para sa maling tanong. Ang pagpaparami ng array na ito ay lumilikha ng temporaryong resulta. Ang pagdaragdag ng mga orihinal na halaga ay lumilikha ng output. Kailangan pa rin ng memorya at naglilipat ng data ang native execution.

3:47 Ang ilang operasyon ay tumatanggap ng output buffer, binabawasan ang mga allocation kapag kaya ng iyong code na ligtas itong gamitin muli. Ang isang magandang linya ay maaaring mag-order ng ilang malalaking buffer. Pinupuna rin ng Python Speed ang problemang ito. Ang allocator ay kapansin-pansing walang pakialam sa iyong aesthetics.

Maaari bang maging mabilis din ang isang compiled na Python loop?

4:00 Maaari mo ring panatilihin ang loop syntax at baguhin ang pagpapatupad nito. Maaaring i-compile ng Numba ang sinusuportahang numerical Python functions sa native code. Narito ang loop mula sa aming test na may compiler decorator nito. Sinasabi pa rin nito na 'for'. Nagbago ang magastos na interpreter path. Pagkatapos ng compilation, ang loop na ito ay umabot ng mas mababa sa kalahating millisecond na may handa na mga array. Ang compilation mismo ay umabot ng halos isang segundo sa pagtakbo na ito. Hindi kasama ang gastos sa pag-setup na iyon sa mga paulit-ulit na timing,

4:22 kaya ang isang maliit na one-off na trabaho ay karapat-dapat sa ibang paghahambing. Masaya ang sariling gabay ng Numba na ipakita ang mga explicit loops. Ang pagsisimula ng paglilipat ng wika bago matukoy ang hot path ay isang detalyadong paraan upang iwasan ang pagbubukas ng isang profiler. Unang alamin kung ano ang kumukonsumo ng oras. Ang network waits, object parsing at bulk arithmetic ay nangangailangan ng iba't ibang pag-aayos. Nakatutulong ang mga native array operation kapag ang kalkulasyon at data ay akma.

4:43 Sukatin ang resultang talagang kailangan ng iyong tumatawag. Ngayon, para sa shortcut na iyon. Mayroon kang function ng Python at gusto mong tanggapin nito ang isang array. Ang isang wrapper na pinangalanang vectorize ay parang ang nawawalang performance button. Mayroon itong mahalagang pangungusap na naghihintay sa dokumentasyon nito.

Ano ang talagang isinasagawa ng np.vectorize?

4:56 Sinasabi ng NumPy na ang vectorize wrapper nito ay ibinibigay pangunahin para sa kaginhawaan. Ang implementasyon nito ay mahalagang isang for loop. Tinatanggap ng wrapper ang mga batch, ngunit patuloy na tinatawag ang iyong function ng Python para sa sunud-sunod na elemento. Umikli ang interface. Naging abala ang execution boundary. Panoorin ang parehong mga halaga na bumalik sa pamamagitan ng Python callback. Sa mga handa na array, ang bersyon na ito ay umabot ng halos walumpu't pitong millisecond. Mas mabagal ito kaysa sa aming comprehension.

5:18 Ang isang kapaki-pakinabang na broadcasting wrapper ay maaaring magpanatili ng eksaktong per element work na sinusubukan mong alisin. Suriin ang implementasyon sa likod ng isang batch interface, panatilihin ang compatible na data sa kapaki-pakinabang nitong anyo, at isama ang conversion sa paghahambing. Ang mga native, callback at compiled loops ay maaaring magmukhang magkatulad mula sa upuan ng tumatawag. Ang pangalang vectorize ay nagbigay ng pangako na hindi kailanman nilagdaan ng iyong stopwatch. Panatilihin ito kung ang kaginhawaan ang kailangan mo. Para sa performance, suriin ang loop na tumatakbo.

Ano ang dapat mong baguhin sa iyong code?

5:41 Ang aking hatol ay SHIP IT para sa pag-batch ng isang sinusukat na numerical hot path. Panatilihin ang mga ordinaryong loop kapag gumagana na nang maayos. Suriin kung saan nangyayari ang trabaho at kung ano ang kailangan ng susunod na tumatawag. Mag-subscribe, pindutin ang bell, at sabihin sa akin sa mga komento kung naiiba mo itong tatatakan. At iyan ang diff para sa araw na ito. Ako si Niko mula sa Axrisi. Mag-merge nang may pananagutan.

Mga Pinagmulan

  1. Universal functions (ufunc) basics — NumPy 2.2NumPy
  2. The N-dimensional array — NumPy 2.2NumPy
  3. numpy.vectorize — convenience and performance notesNumPy
  4. CPU/SIMD optimizations — NumPy 2.2NumPy
  5. dis — Disassembler for Python bytecodePython Software Foundation
  6. CPython 3.10.12 list representationCPython contributors
  7. The limits of Python vectorization as a performance techniqueItamar Turner-Trauring / Python⇒Speed
  8. Performance TipsNumba
  9. Basics of CuPyCuPy

Mga kaugnay na video