วิธีเพิ่มประสิทธิภาพสคริปต์ Python ของคุณเพื่อประสิทธิภาพที่ดีขึ้น

Withi Pheim Prasiththiphaph Skhript Python Khxng Khun Pheux Prasiththiphaph Thi Di Khun



การเพิ่มประสิทธิภาพสคริปต์ Python เพื่อประสิทธิภาพที่ดีขึ้นเกี่ยวข้องกับการระบุและแก้ไขจุดคอขวดในโค้ดของเรา ทำให้รันได้เร็วขึ้นและมีประสิทธิภาพมากขึ้น Python เป็นภาษาโปรแกรมยอดนิยมและทรงพลังที่ใช้ในแอปพลิเคชั่นมากมายในปัจจุบัน รวมถึงการวิเคราะห์ข้อมูล โปรเจ็กต์ ML (การเรียนรู้ของเครื่อง) การพัฒนาเว็บ และอื่นๆ อีกมากมาย การเพิ่มประสิทธิภาพโค้ด Python เป็นกลยุทธ์ในการปรับปรุงความเร็วและประสิทธิภาพของโปรแกรมนักพัฒนาเมื่อดำเนินกิจกรรมใดๆ โดยใช้โค้ดน้อยลง หน่วยความจำน้อยลง หรือทรัพยากรเพิ่มเติม รหัสขนาดใหญ่และไม่มีประสิทธิภาพอาจทำให้โปรแกรมทำงานช้าลง ซึ่งอาจส่งผลให้ลูกค้าได้รับความพึงพอใจต่ำและอาจสูญเสียทางการเงิน หรือจำเป็นต้องทำงานเพิ่มเติมเพื่อแก้ไขและแก้ไขปัญหา

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

  1. เพิ่มประสิทธิภาพของแอปพลิเคชัน
  2. สร้างโค้ดที่สามารถอ่านและจัดระเบียบได้
  3. ทำให้การตรวจสอบข้อผิดพลาดและการดีบักง่ายขึ้น
  4. อนุรักษ์พลังการคำนวณจำนวนมากและอื่นๆ

โปรไฟล์รหัสของคุณ

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







ข้อมูลโค้ด:



นำเข้า ซีโปรไฟล์ เช่น ซีพี
แน่นอน คำนวณผลรวม ( อินพุตหมายเลข ) : :
sum_of_input_numbers = 0
ในขณะที่ อินพุตหมายเลข > 0 : :
sum_of_input_numbers + = อินพุตจำนวน % 10
หมายเลขอินพุต // = 10
พิมพ์ ( 'ผลรวมของตัวเลขทั้งหมดในหมายเลขอินพุตคือ: 'sum_of_input_numbers'' )
กลับ sum_of_input_numbers
แน่นอน main_func ( ) : :
ซีพี. วิ่ง ( 'คำนวณผลรวม (9876543789)' )
ถ้า __ชื่อ__ == '__หลัก__' : :
main_func ( )

โปรแกรมทำการเรียกฟังก์ชันทั้งหมดห้าครั้งดังที่เห็นในบรรทัดแรกของเอาต์พุต รายละเอียดของการเรียกใช้ฟังก์ชันแต่ละครั้งจะแสดงเป็นสองสามบรรทัดต่อไปนี้ รวมถึงจำนวนครั้งที่เรียกใช้ฟังก์ชัน ระยะเวลาโดยรวมในฟังก์ชัน ระยะเวลาต่อการโทร และจำนวนเวลาโดยรวมในฟังก์ชัน (รวมถึง เรียกว่าเป็นฟังก์ชันทั้งหมด)



นอกจากนี้ โปรแกรมจะพิมพ์รายงานบนหน้าจอแจ้งซึ่งแสดงว่าโปรแกรมเสร็จสิ้นเวลาดำเนินการของงานทั้งหมดภายใน 0.000 วินาที นี่แสดงว่าโปรแกรมมีความรวดเร็วแค่ไหน





เลือกโครงสร้างข้อมูลที่เหมาะสม

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



เราประเมินเวลาที่ใช้ในการตรวจสอบว่ามีองค์ประกอบอยู่ในโครงสร้างข้อมูลแต่ละรายการหรือไม่ เช่น รายการ ชุด และพจนานุกรม แล้วเปรียบเทียบ

OptimizeDataType.py:

นำเข้า ไทม์อิ เช่น ทีที
นำเข้า สุ่ม เช่น rndbj
#สร้างรายการจำนวนเต็ม
สุ่ม_ข้อมูล_รายการ = [ rndbj. หยาบคาย ( 1 , 10,000 ) สำหรับ _ ใน พิสัย ( 10,000 ) ]
# สร้างชุดจากข้อมูลเดียวกัน
Random_data_set = ชุด ( สุ่ม_ข้อมูล_รายการ )

# สร้างพจนานุกรมด้วยข้อมูลเดียวกับคีย์
obj_DataDictionary = { หนึ่ง: ไม่มี สำหรับ หนึ่ง ใน สุ่ม_ข้อมูล_รายการ }

# องค์ประกอบที่จะค้นหา (มีอยู่ในข้อมูล)
Random_number_to_find = rndbj. ทางเลือก ( สุ่ม_ข้อมูล_รายการ )

# วัดเวลาในการตรวจสอบสมาชิกในรายการ
รายการ_เวลา = ทีที ไทม์อิ ( แลมบ์ดา : Random_number_to_find ใน สุ่ม_ข้อมูล_รายการ , ตัวเลข = 1,000 )

# วัดเวลาในการตรวจสอบสมาชิกในชุด
ตั้งเวลา = ทีที ไทม์อิ ( แลมบ์ดา : Random_number_to_find ใน Random_data_set , ตัวเลข = 1,000 )

# วัดเวลาในการตรวจสอบความเป็นสมาชิกในพจนานุกรม
dict_time = ทีที ไทม์อิ ( แลมบ์ดา : Random_number_to_find ใน obj_DataDictionary , ตัวเลข = 1,000 )

พิมพ์ ( 'เวลาตรวจสอบการเป็นสมาชิกรายการ: {list_time:.6f} วินาที' )
พิมพ์ ( 'ตั้งเวลาตรวจสอบสมาชิก: {set_time:.6f} วินาที' )
พิมพ์ ( 'เวลาตรวจสอบสมาชิกพจนานุกรม: {dict_time:.6f} วินาที' )

รหัสนี้จะเปรียบเทียบประสิทธิภาพของรายการ ชุด และพจนานุกรมเมื่อทำการตรวจสอบสมาชิก โดยทั่วไป ชุดและพจนานุกรมจะเร็วกว่ารายการสำหรับการทดสอบความเป็นสมาชิกอย่างมาก เนื่องจากใช้การค้นหาแบบแฮช ดังนั้นจึงมีความซับซ้อนของเวลาโดยเฉลี่ยที่ O(1) ในทางกลับกัน รายการต้องทำการค้นหาเชิงเส้นซึ่งส่งผลให้เกิดการทดสอบความเป็นสมาชิกด้วยความซับซ้อนของเวลา O(n)

  ภาพหน้าจอของคำอธิบายคอมพิวเตอร์ที่สร้างขึ้นโดยอัตโนมัติ

ใช้ฟังก์ชันในตัวแทนการวนซ้ำ

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

มาสร้างโค้ดตัวอย่างเพื่อเปรียบเทียบประสิทธิภาพของการสร้างลูปแบบกำหนดเองโดยใช้ฟังก์ชันในตัวสำหรับงานทั่วไป (เช่น map(), filter() และ sorted()) เราจะประเมินว่าวิธีการแมป การกรอง และการเรียงลำดับต่างๆ ทำงานได้ดีเพียงใด

BuiltInFunctions.py:

นำเข้า ไทม์อิ เช่น ทีที
# ตัวอย่างรายการ number_list
ตัวเลข_รายการ = รายการ ( พิสัย ( 1 , 10,000 ) )

# ฟังก์ชั่นในการยกกำลังสอง number_list โดยใช้การวนซ้ำ
แน่นอน square_using_loop ( ตัวเลข_รายการ ) : :
สแควร์_ผลลัพธ์ = [ ]
สำหรับ หนึ่ง ใน ตัวเลข_รายการ:
สแควร์_ผลลัพธ์ ผนวก ( ที่หนึ่ง ** 2 )
กลับ สแควร์_ผลลัพธ์
# ฟังก์ชั่นกรองเลขคู่รายการโดยใช้การวนซ้ำ
แน่นอน filter_even_using_loop ( ตัวเลข_รายการ ) : :
filter_result = [ ]
สำหรับ หนึ่ง ใน ตัวเลข_รายการ:
ถ้า หนึ่ง % 2 == 0 : :
filter_result. ผนวก ( หนึ่ง )
กลับ filter_result
# ฟังก์ชั่นการเรียงลำดับตัวเลข_รายการโดยใช้การวนซ้ำ
แน่นอน sort_using_loop ( ตัวเลข_รายการ ) : :
กลับ จัดเรียง ( ตัวเลข_รายการ )
# วัดเวลาในการยกกำลังสอง number_list โดยใช้ map()
แผนที่_เวลา = ทีที ไทม์อิ ( แลมบ์ดา : : รายการ ( แผนที่ ( แลมบ์ดา x: x ** 2 , ตัวเลข_รายการ ) ) , ตัวเลข = 1,000 )
# วัดเวลาในการกรองเลขคู่โดยใช้ filter()
ตัวกรอง_เวลา = ทีที ไทม์อิ ( แลมบ์ดา : : รายการ ( กรอง ( แลมบ์ดา x: x % 2 == 0 , ตัวเลข_รายการ ) ) , ตัวเลข = 1,000 )
# วัดเวลาในการเรียงลำดับ number_list โดยใช้ sorted()
เรียงลำดับ_เวลา = ทีที ไทม์อิ ( แลมบ์ดา : : จัดเรียง ( ตัวเลข_รายการ ) , ตัวเลข = 1,000 )
# วัดเวลาในการยกกำลังสอง number_list โดยใช้วงวน
loop_map_time = ทีที ไทม์อิ ( แลมบ์ดา : square_using_loop ( ตัวเลข_รายการ ) , ตัวเลข = 1,000 )
# วัดเวลาในการกรองเลขคู่_รายการโดยใช้การวนซ้ำ
loop_filter_time = ทีที ไทม์อิ ( แลมบ์ดา : filter_even_using_loop ( ตัวเลข_รายการ ) , ตัวเลข = 1,000 )
# วัดเวลาในการเรียงลำดับตัวเลข_รายการโดยใช้การวนซ้ำ
loop_sorted_time = ทีที ไทม์อิ ( แลมบ์ดา : sort_using_loop ( ตัวเลข_รายการ ) , ตัวเลข = 1,000 )
พิมพ์ ( 'รายการตัวเลขมี 10,000 องค์ประกอบ' )
พิมพ์ ( 'แผนที่() เวลา: {map_time:.6f} วินาที' )
พิมพ์ ( 'ตัวกรอง () เวลา: {filter_time:.6f} วินาที' )
พิมพ์ ( 'เรียงลำดับ () เวลา: {sorted_time:.6f} วินาที' )
พิมพ์ ( 'เวลาวนรอบ (แผนที่): {loop_map_time:.6f} วินาที' )
พิมพ์ ( 'เวลาวนรอบ (ตัวกรอง): {loop_filter_time:.6f} วินาที' )
พิมพ์ ( 'เวลาวนซ้ำ (เรียงลำดับ): {loop_sorted_time:.6f} วินาที' )

เราน่าจะสังเกตเห็นว่าฟังก์ชันในตัว (map(), filter() และ sorted()) เร็วกว่าลูปแบบกำหนดเองสำหรับงานทั่วไปเหล่านี้ ฟังก์ชันในตัวใน Python นำเสนอแนวทางที่กระชับและเข้าใจง่ายมากขึ้นเพื่อดำเนินงานเหล่านี้ และได้รับการปรับให้เหมาะสมที่สุดเพื่อประสิทธิภาพการทำงาน

ปรับลูปให้เหมาะสม

หากจำเป็นต้องเขียนลูป มีเทคนิคบางอย่างที่เราสามารถทำได้เพื่อเร่งความเร็ว โดยทั่วไปแล้ว range() loop จะเร็วกว่าการวนซ้ำแบบย้อนกลับ นี่เป็นเพราะว่า range() สร้างตัววนซ้ำโดยไม่ต้องกลับรายการซึ่งอาจเป็นการดำเนินการที่มีค่าใช้จ่ายสูงสำหรับรายการที่มีความยาว นอกจากนี้ เนื่องจาก range() ไม่ได้สร้างรายการใหม่ในหน่วยความจำ จึงใช้หน่วยความจำน้อยลง

OptimizeLoop.py:

นำเข้า ไทม์อิ เช่น ทีที
# ตัวอย่างรายการ number_list
ตัวเลข_รายการ = รายการ ( พิสัย ( 1 , 100,000 ) )
# ฟังก์ชั่นเพื่อวนซ้ำรายการในลำดับย้อนกลับ
แน่นอน loop_reverse_iteration ( ) : :
ผลลัพธ์_ย้อนกลับ = [ ]
สำหรับ เจ ใน พิสัย ( เท่านั้น ( ตัวเลข_รายการ ) - - 1 , - - 1 , - - 1 ) : :
ผลลัพธ์_ย้อนกลับ ผนวก ( ตัวเลข_รายการ [ เจ ] )
กลับ ผลลัพธ์_ย้อนกลับ
# ฟังก์ชั่นวนซ้ำรายการโดยใช้ range()
แน่นอน loop_range_iteration ( ) : :
ผลลัพธ์_ช่วง = [ ]
สำหรับ เค ใน พิสัย ( เท่านั้น ( ตัวเลข_รายการ ) ) : :
ผลลัพธ์_ช่วง ผนวก ( ตัวเลข_รายการ [ เค ] )
กลับ ผลลัพธ์_ช่วง
# วัดเวลาที่ใช้ในการทำซ้ำแบบย้อนกลับ
ย้อนกลับ_เวลา = ทีที ไทม์อิ ( loop_reverse_iteration , ตัวเลข = 1,000 )
# วัดเวลาที่ใช้ในการวนซ้ำช่วง
range_time = ทีที ไทม์อิ ( loop_range_iteration , ตัวเลข = 1,000 )
พิมพ์ ( 'รายการหมายเลขมี 100,000 รายการ' )
พิมพ์ ( 'เวลาวนซ้ำ: {reverse_time:.6f} วินาที' )
พิมพ์ ( 'เวลาวนซ้ำ: {range_time:.6f} วินาที' )

หลีกเลี่ยงการเรียกใช้ฟังก์ชันที่ไม่จำเป็น

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

เครื่องมือสำหรับการทำโปรไฟล์

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับประสิทธิภาพของโค้ดของคุณ นอกเหนือจากการสร้างโปรไฟล์ในตัวแล้ว เราสามารถใช้แพ็คเกจการสร้างโปรไฟล์ภายนอก เช่น cProfile, Pyflame หรือ SnakeViz ได้อีกด้วย

ผลลัพธ์แคช

หากโค้ดของเราจำเป็นต้องทำการคำนวณที่มีราคาแพง เราอาจพิจารณาแคชผลลัพธ์เพื่อประหยัดเวลา

การปรับโครงสร้างรหัสใหม่

การปรับโครงสร้างโค้ดใหม่เพื่อให้อ่านและบำรุงรักษาได้ง่ายขึ้นบางครั้งก็เป็นส่วนที่จำเป็นในการเพิ่มประสิทธิภาพ โปรแกรมที่เร็วกว่านั้นอาจจะสะอาดกว่าด้วย

ใช้การรวบรวม Just-in-Time (JIT)

ไลบรารีเช่น PyPy หรือ Numba สามารถจัดเตรียมการคอมไพล์ JIT ซึ่งสามารถเร่งความเร็วโค้ด Python บางประเภทได้อย่างมาก

อัพเกรดไพธอน

ตรวจสอบให้แน่ใจว่าคุณใช้ Python เวอร์ชันล่าสุด เนื่องจากเวอร์ชันที่ใหม่กว่ามักจะมีการปรับปรุงประสิทธิภาพ

ความเท่าเทียมและการเห็นพ้องกัน

สำหรับกระบวนการที่สามารถเป็นแบบขนานได้ ให้ตรวจสอบเทคนิคแบบขนานและการซิงโครไนซ์ เช่น การประมวลผลหลายตัว การทำเธรด หรืออะซิงซิโอ

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

บทสรุป

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