ทำไมต้องรวบรวมไพ ธ อนรหัส?


241

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

ฉันยังสังเกตเห็นว่าบางไฟล์ในแอปพลิเคชันของฉันได้รับการคอมไพล์เป็น. pyc ในขณะที่ไฟล์อื่นไม่ทำทำไมถึงเป็นเช่นนั้น


คุณอาจทราบว่ารวมถึงการเริ่มต้นแอปพลิเคชันของคุณเร็วขึ้นคุณจะได้รับความปลอดภัยหากคุณไม่สามารถแบ่งปันรหัสของคุณได้หากเป็นความลับขององค์กร
Please_Dont_Bully_Me_SO_Lords

@PSyLoCKe คุณทำไม่ได้จริงๆ Python bytecode สามารถอ่านได้จริงเพราะคอมไพเลอร์ไม่จำเป็นต้องทำให้เข้าใจยากเพื่อเพิ่มประสิทธิภาพ (ไม่ว่ามันจะปรับให้เหมาะสมมาก ... )
wizzwizz4

1
สาเหตุที่ไฟล์บางไฟล์ถูกคอมไพล์โดยอัตโนมัติก็เพราะไฟล์เหล่านั้นถูกนำเข้า ตัวอย่างเช่นถ้าคุณใช้import mylib.pyPython จะรวบรวมmylib.pyเพื่อให้importงบในอนาคตทำงานได้เร็วขึ้นเล็กน้อย หากคุณเปลี่ยนแปลงในภายหลังmylib.pyจะได้รับการรวบรวมอีกครั้งในครั้งถัดไปที่นำเข้า (Python ใช้วันที่ของไฟล์เพื่อดูว่าเกิดเหตุการณ์นี้ขึ้น)
fyngyrz

คำตอบ:


270

มันถูกคอมไพล์ด้วยโค้ดไบต์ซึ่งสามารถใช้งานได้มากเร็วกว่ามาก

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

การเพิ่มที่สำคัญโดยBen Blank :

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


260
เป็นที่น่าสังเกตว่าในขณะที่เรียกใช้สคริปต์ที่รวบรวมมีเวลาเริ่มต้นที่เร็วขึ้น(เนื่องจากไม่จำเป็นต้องรวบรวม) แต่ก็ไม่ได้ทำงานได้เร็วขึ้น
Ben Blank

24
ความเข้าใจผิดที่พบบ่อย ขอบคุณสำหรับการแบ่งปัน.
matpie

1
นอกเหนือจากการไม่ต้องการคอมไพล์แล้วไฟล์. pyc มีขนาดเล็กลงเกือบตลอดเวลา โดยเฉพาะถ้าคุณแสดงความคิดเห็นมาก หนึ่งในของฉันคือ 28419 เช่น. py แต่มีเพียง 1,7879 ในฐานะ. pyc - ดังนั้นความเร็วในการโหลดก็ดีขึ้นเช่นกัน สุดท้ายคุณสามารถคอมไพล์สคริปต์ระดับบนสุดล่วงหน้าด้วยวิธีนี้: python -m compileall myscript.py
fyngyrz

1
มีความแตกต่างในการใช้หน่วยความจำหรือไม่? ฉันกำลังทดสอบ Python บนอุปกรณ์ฝังตัวโดยใช้ mips cpu ที่มี RAM เพียง 64MB ดังนั้นจะมีข้อได้เปรียบอะไรบ้างในการใช้หน่วยความจำเมื่อเริ่มต้นสคริปต์ไพ ธ อนที่คอมไพล์แล้ว?
valentt

1
@valentt: อาจจะไม่ ฉันไม่รู้อะไรเกี่ยวกับ Python internals มากนัก แต่ฉันไม่คิดว่าการแยกวิเคราะห์ bytecode ใช้หน่วยความจำจำนวนมากใน Python ฉันไม่สามารถนึกถึงบางสิ่งที่ต้องใช้หน่วยความจำจำนวนมากเพื่อจดจำสถานะบางอย่าง
Georg Schölly

80

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

"An Introduction to Python" กล่าวถึงสิ่งนี้เกี่ยวกับไฟล์ Python ที่คอมไพล์แล้ว:

โปรแกรมจะไม่ทำงานเร็วขึ้นเมื่ออ่านจากไฟล์ '.pyc' หรือ '.pyo' มากกว่าเมื่ออ่านจากไฟล์ '.py' สิ่งเดียวที่เร็วขึ้นเกี่ยวกับไฟล์ '.pyc' หรือ '.pyo' คือความเร็วในการโหลด

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

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

สคริปต์ที่คุณตั้งชื่อในบรรทัดคำสั่งจะไม่ถูกบันทึกลงในไฟล์. pyc เฉพาะโมดูลที่โหลดโดยสคริปต์ "หลัก" นั้นจะถูกบันทึกในลักษณะนั้น


3
ในหลายกรณีมันยากที่จะเห็นความแตกต่าง แต่ฉันมีไฟล์ไพ ธ อนที่มีมากกว่า 300,000 บรรทัด (เป็นกลุ่มของการคำนวณทางคณิตศาสตร์ที่สร้างโดยสคริปต์อื่นสำหรับการทดสอบ) ใช้เวลารวบรวม 37 วินาทีและใช้เวลาเพียง 2 วินาทีในการดำเนินการ
wojtow

54

ข้อดี:

ครั้งแรก: อ่อนเพลีย obfuscation พ่ายแพ้

ข้อสอง: หากการคอมไพล์ส่งผลให้ไฟล์มีขนาดเล็กลงอย่างมีนัยสำคัญคุณจะได้รับเวลาโหลดเร็วขึ้น ดีสำหรับเว็บ

ประการที่สาม: Python สามารถข้ามขั้นตอนการรวบรวมได้ เร็วขึ้นที่โหลดเริ่มต้น ดีสำหรับซีพียูและเว็บ

ข้อที่สี่: ยิ่งคุณแสดงความคิดเห็นมากเท่าใดไฟล์.pycหรือ.pyoไฟล์ขนาดเล็กก็จะยิ่งถูกเปรียบเทียบกับ.pyไฟล์ต้นฉบับ

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

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

การรวบรวมระดับสูงสุด

มีประโยชน์ที่จะทราบว่าคุณสามารถรวบรวมไฟล์ไพ ธ อนระดับบนสุดเป็น.pycไฟล์ด้วยวิธีนี้:

python -m py_compile myscript.py

สิ่งนี้จะลบความคิดเห็น มันทิ้งdocstringsเหมือนเดิม หากคุณต้องการกำจัดdocstringsเช่นกัน (คุณอาจต้องคิดอย่างจริงจังว่าทำไมคุณถึงทำอย่างนั้น) จากนั้นรวบรวมวิธีนี้แทน ...

python -OO -m py_compile myscript.py

... และคุณจะได้รับ.pyoไฟล์แทน.pycไฟล์; แจกจ่ายอย่างเท่าเทียมกันในแง่ของการทำงานที่สำคัญของรหัส แต่มีขนาดเล็กตามขนาดของถอดออกdocstrings(และไม่เข้าใจได้อย่างง่ายดายสำหรับการจ้างงานตามมาถ้ามันมีดีdocstringsในครั้งแรก) แต่ดูข้อเสียเปรียบสามด้านล่าง

โปรดทราบว่าไพ ธ อนใช้.pyวันที่ของไฟล์หากมีอยู่เพื่อตัดสินใจว่าควรรัน.pyไฟล์ตรงข้ามกับ.pycหรือ.pyoไฟล์ --- ดังนั้นให้แก้ไขไฟล์. py ของคุณและ.pycหรือ.pyoล้าสมัยและประโยชน์ใด ๆ ที่คุณได้รับจะหายไป คุณต้องคอมไพล์อีกครั้งเพื่อรับประโยชน์.pycหรือ.pyoกลับมาอีกครั้งเช่นพวกเขาอาจจะ

ข้อเสีย:

ข้อแรก: มี "เวทคุกกี้" ใน.pycและ.pyoไฟล์ที่ระบุสถาปัตยกรรมของระบบที่รวบรวมไฟล์ไพ ธ อนหากคุณแจกจ่ายไฟล์เหล่านี้หนึ่งไฟล์ในสภาพแวดล้อมที่แตกต่างกัน หากคุณแจกจ่าย.pycหรือ.pyoไม่เชื่อมโยง.pyเพื่อคอมไพล์ใหม่หรือtouchดังนั้นจึงแทนที่.pycหรือ.pyoผู้ใช้ไม่สามารถแก้ไขได้

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

ประการที่สาม: -OOตัวเลือกPython ยังใช้การปรับแต่งบางอย่างตาม-Oตัวเลือกบรรทัดคำสั่ง ซึ่งอาจส่งผลให้เกิดการเปลี่ยนแปลงในการดำเนินงาน การเพิ่มประสิทธิภาพที่รู้จักคือ:

  • sys.flags.optimize = 1
  • assert งบถูกข้ามไป
  • __debug__ = เท็จ

ข้อที่สี่: ถ้าคุณตั้งใจทำให้สคริปต์ไพ ธ อนของคุณสามารถทำงานได้บางอย่างตามคำสั่งของ#!/usr/bin/pythonบรรทัดแรกสิ่งนี้จะถูกแยกออกมา.pycและ.pyoไฟล์และการทำงานนั้นจะหายไป

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


10

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

ด้วยภาษาที่ใช้ระหว่างกันเมื่อมีการใช้ไฟล์กระบวนการจะมีลักษณะดังนี้:
1. ไฟล์ถูกประมวลผลโดย interpeter
2. ไฟล์ถูกคอมไพล์
3. คอมไพล์รหัสจะถูกดำเนินการ

เห็นได้ชัดว่าใช้โค้ดที่คอมไพล์แล้วคุณสามารถกำจัดขั้นตอนที่ 2 ได้ซึ่งใช้ python, PHP และอื่น ๆ

นี่เป็นบล็อกโพสต์ที่น่าสนใจซึ่งอธิบายความแตกต่างhttp://julipedia.blogspot.com/2004/07/compiled-vs-interpreted-languages.html
และนี่คือรายการที่อธิบายถึงกระบวนการรวบรวม Python http://effbot.org/zone /python-compile.htm


9

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

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

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ในเอกสารหลาม


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

1
@ Josh ที่เป็นไปได้เสมอหากมีใครสามารถเข้าถึงหน่วยความจำหรือดูคำแนะนำในซีพียูมีเวลาเพียงพอและพวกเขาจะสามารถสร้างแอปของคุณได้อีกครั้ง
UnkwnTech

5
ตกลงอย่างไรก็ตามตามที่ Unkwntech กล่าวว่าจะเป็นไปได้เสมอหากบุคคลนั้นได้รับการพิจารณาอย่างเพียงพอ แต่ฉันเชื่อว่ามันจะพอเพียงมากที่สุดในสถานการณ์ที่คุณมักจะเพียงแค่ต้องการที่จะ จำกัด คนจาก "แก้ไข" รหัสของคุณ ...
ไซมอนเซ่นบี

ภาษาที่ถูกคอมไพล์ไปยัง bytecode นั้นโดยทั่วไปไม่ใช่ทั้งหมดที่ยากที่จะทำการคอมไพล์ย้อนกลับเว้นแต่ว่าคุณใช้ขั้นตอนพิเศษเพื่อทำให้งงงวยพวกเขา - เพียงแค่การคอมไพล์โดยทั่วไปจะไม่เพียงพอ
EJoshuaS - Reinstate Monica

7

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


7

บางสิ่งบางอย่างไม่ได้สัมผัสกับเป็นแหล่งที่มาของการแหล่งรวบรวม ตัวอย่างเช่นnuitkaแปลรหัส Python เป็น C / C ++ และคอมไพล์รหัส Binary ที่รันบน CPU โดยตรงแทนที่จะเป็น Python bytecode ที่ทำงานบนเครื่องเสมือนที่ช้ากว่า

สิ่งนี้สามารถนำไปสู่การเร่งความเร็วอย่างมีนัยสำคัญหรือจะช่วยให้คุณทำงานกับ Python ได้ในขณะที่สภาพแวดล้อมของคุณขึ้นอยู่กับรหัส C / C ++


4

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


2

ใช่ประสิทธิภาพเป็นเหตุผลหลักและเท่าที่ฉันรู้เหตุผลเดียวเท่านั้น

หากไฟล์บางไฟล์ของคุณไม่ได้รับการรวบรวมบางที Python อาจไม่สามารถเขียนไปยังไฟล์. pyc ได้อาจเป็นเพราะสิทธิ์ไดเรกทอรีหรือบางอย่าง หรือบางทีไฟล์ที่ยังไม่ได้คอมไพล์ก็ไม่เคยโหลด ... (สคริปต์ / โมดูลจะถูกคอมไพล์เมื่อมันถูกโหลดครั้งแรก)


1

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

คอมไพเลอร์: คอมไพเลอร์เป็นส่วนหนึ่งของรหัสที่แปลภาษาระดับสูงเป็นภาษาเครื่อง

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

แหล่งที่มา: http://www.toptal.com/python/why-are-there-so-many-pythons http://www.engineersgarage.com/contribution/difference-between-compiler-and-interpreter


9
คำจำกัดความของ "compiler" ของคุณไม่ถูกต้อง คอมไพเลอร์ไม่เคยอยู่ภายใต้การคอมไพล์ไปยังรหัสเครื่อง คอมไพเลอร์เป็นเพียงนักแปลจากภาษาหนึ่งไปอีกภาษาหนึ่ง นี่คือเหตุผลที่เราบอกว่า Python "คอมไพล์" กับ bytecode, Coffeescript "คอมไพล์" ถึง Javascript และอื่น ๆ
Ricky Stewart
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.