+− THE DAILY DIFFdev & AI news
SHIP IT

ประสิทธิภาพของ Python: ลูป NumPy แบบเนทีฟ, Callbacks และค่าใช้จ่ายในการแปลง

การทดสอบตัวเลขที่ควบคุมด้วย CPU เท่านั้น ติดตามค่าที่เหมือนกันผ่านลูป CPython, การคำนวณ NumPy, Wrapper Callback ของ Python และลูป Numba ที่คอมไพล์แล้ว NumPy ที่มีอินพุตพร้อมใช้งานมีผลนำอย่างมาก ในขณะที่การแปลงจากและกลับไปเป็นรายการ Python ลดข้อดีนั้นให้เกือบเท่ากัน ตอนนี้อธิบายถึงขอบเขตการดำเนินการและวิธีวัดผลลัพธ์ที่แอปพลิเคชันต้องการ

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

การทดสอบตัวเลขที่ควบคุมด้วย CPU เท่านั้น ติดตามค่าที่เหมือนกันผ่านลูป CPython, การคำนวณ NumPy, Wrapper Callback ของ Python และลูป Numba ที่คอมไพล์แล้ว NumPy ที่มีอินพุตพร้อมใช้งานมีผลนำอย่างมาก ในขณะที่การแปลงจากและกลับไปเป็นรายการ Python ลดข้อดีนั้นให้เกือบเท่ากัน ตอนนี้อธิบายถึงขอบเขตการดำเนินการและวิธีวัดผลลัพธ์ที่แอปพลิเคชันต้องการ

อ่านฉบับลายลักษณ์อักษร (ภาษาอังกฤษ) ↗

วิดีโอนี้ครอบคลุมอะไรบ้าง

  • CPython คอมไพล์ซอร์สโค้ดเป็น bytecode การทำงานของ interpreter/object ซ้ำๆ และลูปตัวเลขเนทีฟที่มีประเภทเป็นการจัดเรียงการดำเนินการที่แตกต่างกัน
  • การคำนวณเชิงตัวเลขของ NumPy สามารถส่งชุดข้อมูลที่มีประเภทไปยังการดำเนินการที่คอมไพล์แล้วได้ ลูปการคำนวณยังคงมีอยู่ และมุมมองสามารถมีโครงสร้างที่ไม่ต่อเนื่องกันได้
  • วัดการแปลงและการแสดงผลลัพธ์ที่ต้องการ ในการรันนี้ การแปลงรายการ Python เป็นอาร์เรย์และย้อนกลับลบข้อได้เปรียบของอาร์เรย์ที่พร้อมใช้งานจำนวนมาก
  • ภาระงานขนาดเล็กอาจชอบ Python ทั่วไปเนื่องจากค่าใช้จ่ายคงที่ในการเรียกอาร์เรย์มีความสำคัญ การทำความเข้าใจแปดค่าชนะการเปรียบเทียบที่วัดได้นี้
  • np.vectorize เป็น Wrapper ที่สะดวกสบายที่เรียก Python สำหรับองค์ประกอบที่ต่อเนื่องกัน อินเทอร์เฟซแบบแบทช์เพียงอย่างเดียวไม่สามารถสร้างการดำเนินการตัวเลขแบบเนทีฟได้
  • ลูปไวยากรณ์ Python ที่คอมไพล์แล้วก็สามารถเร็วได้เช่นกัน รวมถึงค่าใช้จ่ายในการคอมไพล์/ตั้งค่าเมื่อเริ่มต้นเมื่อมีความสำคัญต่อผู้เรียก
  • การดำเนินการแบบเนทีฟ, CPU SIMD, Multithreading และแบ็คเอนด์ GPU เป็นแนวคิดที่แยกจากกัน คุณสมบัติ CPU ที่มีอยู่ไม่ได้ติดตามคำสั่งที่ใช้ในการรันที่เฉพาะเจาะจง

บทถอดเสียงที่แปลแล้ว

แปลจากการบรรยายภาษาอังกฤษต้นฉบับ เสียงและคำบรรยายที่มีให้จะควบคุมโดย YouTube

ทำไม CPU ตัวเดียวกันถึงเสร็จเร็วขึ้นได้?

0:00 คุณคิดว่า Python ต้องการภาษาใหม่เพื่อให้เร็วขึ้น CPU ตัวเดียวกันรันชุดข้อมูลของเราเร็วขึ้นหลังจากที่ย้ายลูป งานหายไปไหน? ความเร็วจะหายไปเมื่อใด? ทางลัดใดที่นำ Python กลับมา? นี่คือ The Daily Diff, ภายใต้ฝากระโปรง จับตาดูทางลัดนั้นไว้ CPython คือการใช้งาน Python มาตรฐาน

0:17 มันคอมไพล์ซอร์สโค้ดของคุณเป็น bytecode จากนั้นรันคำสั่งเหล่านั้นใน interpreter NumPy เป็นไลบรารีตัวเลขที่อาร์เรย์เก็บค่าที่มี ประเภทข้อมูลที่ประกาศไว้ การคำนวณที่สร้างขึ้นสามารถส่งชุดข้อมูลทั้งหมดไปยังการดำเนินการที่คอมไพล์แล้วได้ ลองใช้ค่าจุดทศนิยมหนึ่งล้านค่า ยกกำลังสองแต่ละค่า จากนั้นเพิ่มค่าเริ่มต้น ทุกเวอร์ชันได้รับค่าที่เหมือนกันและให้คำตอบที่ตรงกัน ค่ามีขนาดเล็กพอที่จะป้องกันความแตกต่างของการปัดเศษออกจากการแข่งขัน

0:40 บนเครื่องนี้ การทำความเข้าใจใช้เวลาประมาณสามสิบสามมิลลิวินาที NumPy ใช้เวลาน้อยกว่าหนึ่งมิลลิวินาที ทั้งสองทำงานบน CPU นั่นเป็นหลักฐานที่เป็นประโยชน์สำหรับภาระงานนี้ และเป็นข่าวร้ายสำหรับ ภาษาโปรแกรม เริ่มต้นด้วยลูปปกติ

ลูป Python ทำงานซ้ำอะไรบ้าง?

0:53 Python ได้รับค่าถัดไป ทำการคำนวณ และเพิ่มคำตอบ จากนั้นก็ทำซ้ำอีกครั้ง การคูณมีราคาถูก การจัดเตรียมการคูณครั้งถัดไป และการจัดการกับวัตถุ Python รอบๆ เพิ่มงานทุกครั้ง นี่คือการแยกส่วนของฟังก์ชันที่ทดสอบจริง การวนซ้ำ การคูณ และการบวกปรากฏเป็นคำสั่ง bytecode เวอร์ชันและ interpreter ของ Python เลือกแตกต่างกัน

1:14 ช่วงเวลาเหล่านี้เป็นของเวอร์ชันที่แสดงบนหน้าจอ ซึ่งก็คือ Python 3.10 รายการ Python เก็บการอ้างอิงถึงวัตถุ ดังนั้นสิ่งของประเภทต่างๆ จึงสามารถ ใช้รายการร่วมกันได้ งานคำนวณของเราใช้ตัวเลขตลอด มันจ่ายสำหรับการจัดเตรียมทั่วไปในขณะที่ร้องขอบริการที่ซ้ำซาก ลองนึกภาพการสั่งกาแฟแก้วเดียวกันเป็นล้านครั้งและกรอกแบบฟอร์มใหม่ สำหรับทุกแก้ว เครื่องชงกาแฟก็ใช้ได้

1:36 งานเอกสารกลับมีอาชีพเป็นของตัวเอง

NumPy ย้ายลูปไปที่ไหน?

1:38 NumPy เปลี่ยนสัญญา อาร์เรย์นี้เก็บค่าจุดทศนิยมขนาดคงที่ที่มีประเภทที่ประกาศไว้เพียงประเภทเดียว อาร์เรย์ของเราเป็นแบบต่อเนื่อง ดังนั้นค่าต่างๆ จึงอยู่รวมกันในหน่วยความจำ มุมมองสามารถมีโครงสร้างอื่นได้ การดำเนินการคำนวณรู้ว่ากำลังรับข้อมูลประเภทใด การเรียกจะส่งชุดข้อมูลไปยังการดำเนินการแบบเนทีฟ ลูปยังคงเข้าถึงค่าภายในโค้ดที่คอมไพล์แล้ว มันสามารถใช้ความรู้เกี่ยวกับประเภทซ้ำๆ ในการทำงานนั้นได้

2:00 Python ยังคงเป็นผู้ส่งมอบงาน Itamar Turner Trauring อธิบายความแตกต่างใน Python Speed อินเทอร์เฟซแบบแบทช์ การนำไปใช้งานแบบเนทีฟ และคำสั่งเวกเตอร์ของโปรเซสเซอร์เป็น สิ่งต่างๆ ที่แยกจากกัน ชื่อฟังก์ชันให้หลักฐานน้อยมาก

เร็วหมายถึง GPU หรือหลายคอร์ CPU หรือไม่?

2:13 ผลลัพธ์นี้ใช้ NumPy บน CPU แบ็คเอนด์ GPU เช่น CuPy เลือกตำแหน่งอื่นสำหรับอาร์เรย์และการดำเนินการ การซื้อ GPU ทำให้ลูป Python ทั่วไปนี้ยังคงทำงานในที่ที่มันทำงานอยู่แล้ว คำสั่งเวกเตอร์ของ CPU สามารถประมวลผลหลายค่าพร้อมกันได้ NumPy มีกลไกในการเลือกเคอร์เนลที่รองรับ รันไทม์ของเรารายงานคุณสมบัติที่มีอยู่ แต่ไม่ได้ติดตามคำสั่งของนิพจน์นี้ การให้ gain ที่วัดได้ทั้งหมดแก่คำสั่งเวกเตอร์จะเป็นการ โฆษณาเกินจริง

2:40 ตะกร้าสินค้า GPU ยังคงปิดอยู่ มีบางอย่างที่น่าพึงพอใจอย่างยิ่งเกี่ยวกับการแก้ไขประสิทธิภาพที่ยังยกเลิกการ ซื้อได้ด้วย น่าเสียดายที่เกณฑ์มาตรฐานยังคงดำเนินต่อไป

ความเร็วที่น่าประทับใจจะหายไปเมื่อใด?

2:49 ด้วยแปดค่า การทำความเข้าใจชนะ การเรียกกลไกอาร์เรย์มีค่าใช้จ่ายมากกว่างานเล็กๆ อาร์เรย์พร้อมใช้งานที่ใหญ่ขึ้นดึงขึ้นนำ เราใช้การทดลองซ้ำและกระบวนการที่อุ่นเครื่องแล้ว บิลด์ Python รุ่นใหม่สามารถเปลี่ยนจุดตัดได้ จากนั้นเปลี่ยนสิ่งที่แอปพลิเคชันต้องการ เริ่มต้นด้วยรายการ Python และจบด้วยรายการ Python ใหม่ NumPy ต้องแปลงอินพุตเป็นอาร์เรย์และเปลี่ยนคำตอบกลับเป็นวัตถุ Python

3:11 ขั้นตอนเหล่านั้นเป็นส่วนหนึ่งของค่าใช้จ่ายหากแอปพลิเคชันของคุณต้องการ ที่ค่าหนึ่งล้านค่า เส้นทางที่สมบูรณ์นั้นใช้เวลาประมาณยี่สิบแปดมิลลิวินาที การทำความเข้าใจก็ใช้เวลาประมาณยี่สิบแปดมิลลิวินาทีเช่นกัน การนำที่น่าทึ่งของเรากลายเป็นการเสมอเกือบเท่ากัน ส่วนที่เร็วเป็นเรื่องจริง ข้อได้เปรียบขึ้นอยู่กับการปล่อยให้ข้อมูลอยู่ในรูปแบบตัวเลข

ขอบเขตใดที่ควรอยู่ในเกณฑ์มาตรฐาน?

3:28 ติดตามข้อมูล หากการดำเนินการถัดไปรับอาร์เรย์ ให้เก็บอาร์เรย์ไว้ หากคุณแปลงระหว่างรายการและอาร์เรย์ซ้ำๆ ให้วัดการข้ามเหล่านั้น การหยุดก่อนการส่งมอบที่มีค่าใช้จ่ายสูงจะให้ตัวเลขที่ถูกต้องสำหรับคำถามที่ผิด การคูณอาร์เรย์นี้สร้างผลลัพธ์ชั่วคราว การเพิ่มค่าเริ่มต้นสร้างเอาต์พุต การดำเนินการแบบเนทีฟยังคงต้องการหน่วยความจำและย้ายข้อมูล

3:47 การดำเนินการบางอย่างยอมรับบัฟเฟอร์เอาต์พุต ซึ่งช่วยลดการจัดสรรเมื่อโค้ดของคุณสามารถ นำกลับมาใช้ใหม่ได้อย่างปลอดภัย หนึ่งบรรทัดที่สวยงามสามารถสั่งบัฟเฟอร์ขนาดใหญ่หลายตัวได้ Python Speed ก็ชี้ให้เห็นปัญหานี้เช่นกัน allocator ไม่สนใจสุนทรียภาพของคุณอย่างน่าประหลาดใจ

ลูป Python ที่คอมไพล์แล้วก็เร็วได้ด้วยหรือไม่?

4:00 คุณยังสามารถรักษารูปแบบลูปและเปลี่ยนการดำเนินการได้ Numba สามารถคอมไพล์ฟังก์ชัน Python เชิงตัวเลขที่รองรับเป็นโค้ดเนทีฟได้ นี่คือลูปจากการทดสอบของเราพร้อมด้วย decorator ของคอมไพเลอร์ มันยังคงเขียนว่า for เส้นทาง interpreter ที่มีค่าใช้จ่ายสูงได้เปลี่ยนไปแล้ว หลังจากคอมไพล์ ลูปนี้ใช้เวลาน้อยกว่าครึ่งมิลลิวินาทีกับอาร์เรย์ที่พร้อมใช้งาน การคอมไพล์เองใช้เวลาประมาณหนึ่งวินาทีในการรันนี้ ค่าใช้จ่ายในการตั้งค่านั้นถูกยกเว้นจากการจับเวลาซ้ำๆ

4:22 ดังนั้นงานเล็กๆ น้อยๆ เพียงครั้งเดียวจึงควรได้รับการเปรียบเทียบที่แตกต่างกัน คู่มือของ Numba เองก็ยินดีที่จะแสดงลูปที่ชัดเจน การเริ่มต้นการโยกย้ายภาษาโดยไม่พบ hot path เป็นวิธีที่ซับซ้อนในการ หลีกเลี่ยงการเปิด profiler ขั้นแรกให้หาสิ่งที่ใช้เวลา การรอเครือข่าย การแยกวิเคราะห์วัตถุ และการคำนวณจำนวนมากต้องการการแก้ไขที่แตกต่างกัน การดำเนินการอาร์เรย์แบบเนทีฟช่วยได้เมื่อการคำนวณและข้อมูลเข้ากันได้

4:43 วัดผลลัพธ์ที่ผู้เรียกของคุณต้องการจริงๆ ตอนนี้สำหรับทางลัดนั้น คุณมีฟังก์ชัน Python และต้องการให้มันยอมรับอาร์เรย์ Wrapper ที่ชื่อ vectorize ดูเหมือนปุ่มประสิทธิภาพที่ขาดหายไป เอกสารประกอบมีประโยคสำคัญรออยู่

np.vectorize ทำงานอะไรจริงๆ?

4:56 NumPy กล่าวว่า wrapper vectorize ของมันมีไว้เพื่อความสะดวกเป็นหลัก การนำไปใช้งานเป็นหลักคือลูป for Wrapper ยอมรับชุดข้อมูล แต่ยังคงเรียกฟังก์ชัน Python ของคุณสำหรับ องค์ประกอบที่ต่อเนื่องกัน อินเทอร์เฟซสั้นลง ขอบเขตการดำเนินการยังคงยุ่งอยู่ ดูค่าเดียวกันกลับมาผ่าน callback ของ Python ด้วยอาร์เรย์ที่พร้อมใช้งาน เวอร์ชันนี้ใช้เวลาประมาณแปดสิบเจ็ดมิลลิวินาที มันช้ากว่าการทำความเข้าใจของเรา

5:18 Wrapper การกระจายที่ใช้งานได้สามารถรักษางานแต่ละองค์ประกอบที่คุณพยายามจะ ลบออกได้ ตรวจสอบการนำไปใช้งานเบื้องหลังอินเทอร์เฟซแบบแบทช์ เก็บข้อมูลที่เข้ากันได้ในรูปแบบที่เป็นประโยชน์ และรวมการแปลงในการเปรียบเทียบ และรวมการแปลงในการเปรียบเทียบ ลูปแบบเนทีฟ, callback และคอมไพล์สามารถดูคล้ายกันจากมุมมองของผู้เรียก ชื่อ vectorize ให้คำมั่นสัญญาที่นาฬิกาจับเวลาของคุณไม่เคยเซ็นรับรอง เก็บไว้เมื่อความสะดวกสบายคือสิ่งที่คุณต้องการ สำหรับประสิทธิภาพ ให้ตรวจสอบลูปที่ทำงาน

คุณควรเปลี่ยนอะไรในโค้ดของคุณ?

5:41 คำตัดสินของฉันคือ SHIP IT สำหรับการจัดกลุ่ม hot path เชิงตัวเลขที่วัดได้ เก็บลูปปกติไว้เมื่อมันทำงานได้ดีอยู่แล้ว ตรวจสอบว่างานเกิดขึ้นที่ไหนและผู้เรียกคนถัดไปต้องการอะไร สมัครสมาชิก กดกระดิ่ง และบอกฉันในความคิดเห็นว่าคุณจะประทับตรามัน แตกต่างกันหรือไม่ และนั่นคือความแตกต่างสำหรับวันนี้ ฉันชื่อ Niko จาก Axrisi รวมอย่างมีความรับผิดชอบ

แหล่งที่มา

  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

วิดีโอที่เกี่ยวข้อง

under-the-hood · th · 8 ต.ค. 2569

Polars 2.0: เหตุใดการ join จึงไม่รักษาลำดับแถวอีกต่อไป

Polars 2.0 รัน collect บน streaming engine เป็นค่าเริ่มต้น สำหรับ join, group_by และ unpivot เวอร์ชันนี้ไม่รับประกันลำดับแถวของอินพุตอีกต่อไป เว้นแต่คุณจะตั้งค่า maintain_order หรือ sort อย่างชัดเจน ใ

2:31 ↗
under-the-hood · th · 12 ต.ค. 2569

ไฟล์โมเดล Hugging Face สามารถรันโค้ดที่ซ่อนอยู่ได้

แพ็คเกจโมเดลที่เป็นอันตรายสามารถรันโค้ดได้ในระหว่างการโหลดที่ไม่ปลอดภัย มีตัวอย่างที่จัดทำเป็นเอกสารสามตัวอย่างที่อธิบาย Pickle reverse shells, พฤติกรรมของเครื่องสแกนไฟล์ที่เสียหาย และความสับสนของชื่อ

3:33 ↗
under-the-hood · th · 11 ต.ค. 2569

Stripe จดจำคำขอของคุณเมื่อการตอบกลับหายไป

การหมดเวลาอาจทำให้การชำระเงินไม่แน่นอนหลังจากที่เซิร์ฟเวอร์ดำเนินการเสร็จสิ้น คำอธิบาย Under the Hood นี้ใช้สัญญา idempotency ที่บันทึกไว้ของ Stripe API v1 เพื่อแสดงคีย์การทำงานที่เสถียร การเล่นซ้ำการ

2:54 ↗
under-the-hood · th · 10 ต.ค. 2569

Shopify ย้ายการจองสินค้าคงคลังไปที่ MySQL

Shopify ย้ายระบบการจองสินค้าคงคลังจาก Redis ไปยังฐานข้อมูล MySQL ซึ่งเป็นที่จัดเก็บข้อมูลบัญชีสินค้าคงคลังอยู่แล้ว กลุ่มแถวของหน่วยที่สามารถล็อกได้ทีละรายการในขอบเขตที่กำหนดช่วยให้การชำระเงินที่เกิดขึ

2:58 ↗