Tại sao phải biên dịch mã Python?


241

Tại sao bạn sẽ biên dịch một tập lệnh Python? Bạn có thể chạy chúng trực tiếp từ tệp .py và nó hoạt động tốt, vậy có lợi thế về hiệu suất hay cái gì không?

Tôi cũng nhận thấy rằng một số tệp trong ứng dụng của tôi được biên dịch thành .pyc trong khi những tệp khác thì không, tại sao lại như vậy?


Bạn cũng có thể lưu ý rằng, bao gồm cả việc khởi động ứng dụng của bạn nhanh hơn, bạn cũng có được sự bảo mật, nếu bạn không thể chia sẻ mã của mình nếu đó là bí mật của công ty.
Xin vui lòng_Dont_Bully_Me_SO_Lords

@PSyLoCKe Bạn thực sự, thực sự không. Python bytecode thực sự có thể đọc được, bởi vì trình biên dịch không cần phải làm xáo trộn nó để tối ưu hóa nó. (Không phải là nó tối ưu hóa nó nhiều ...)
wizzwizz4

1
Lý do một số tệp được biên dịch tự động là vì chúng được nhập; chẳng hạn, nếu bạn sử dụng import mylib.py, Python sẽ biên dịch mylib.pyđể các importcâu lệnh trong tương lai chạy nhanh hơn một chút. Nếu sau này bạn thay đổi mylib.py, thì nó sẽ được biên dịch lại vào lần nhập sau (Python sử dụng ngày tệp để thấy điều này xảy ra.)
fyngyrz

Câu trả lời:


269

Nó được biên dịch thành mã byte, có thể được sử dụng nhiều, nhanh hơn nhiều.

Lý do một số tệp không được biên dịch là tập lệnh chính mà bạn gọi với python main.pyđược biên dịch lại mỗi khi bạn chạy tập lệnh. Tất cả các tập lệnh nhập sẽ được biên dịch và lưu trữ trên đĩa.

Bổ sung quan trọng của Ben Blank :

Điều đáng chú ý là trong khi chạy tập lệnh được biên dịch có thời gian khởi động nhanh hơn (vì nó không cần phải biên dịch), nó không chạy nhanh hơn.


259
Điều đáng chú ý là trong khi chạy tập lệnh được biên dịch có thời gian khởi động nhanh hơn (vì nó không cần phải biên dịch), nó không chạy nhanh hơn.
Ben Trống

24
Một quan niệm sai lầm phổ biến. Cám ơn vì đã chia sẻ.
matpie

1
Ngoài việc không yêu cầu biên dịch, tệp .pyc gần như nhỏ hơn. Đặc biệt nếu bạn bình luận nhiều. Một trong số của tôi là 28419 là .py, nhưng chỉ có 17879 là .pyc - vì vậy thời gian tải cũng tốt hơn. Cuối cùng, bạn có thể biên dịch trước các tập lệnh cấp cao nhất theo cách này: python -m compileall myscript.py
fyngyrz

1
Có sự khác biệt trong tiêu thụ bộ nhớ? Tôi đang thử nghiệm Python trên các thiết bị nhúng dựa trên mips cpu chỉ với 64 MB RAM, vậy có lợi thế nào trong việc sử dụng bộ nhớ khi bắt đầu một phiên bản được biên dịch của tập lệnh python không?
valentt

1
@valentt: Có lẽ là không. Tôi không biết nhiều về các phần bên trong Python, nhưng tôi không nghĩ rằng việc phân tích cú pháp theo mã byte chiếm nhiều bộ nhớ trong Python. Tôi không thể nghĩ ra thứ gì đó cần nhiều bộ nhớ để nhớ một số trạng thái.
Georg Schölly

80

Tệp .pyc là Python đã được biên dịch thành mã byte. Python tự động chạy tệp .pyc nếu nó tìm thấy một tệp có cùng tên với tệp .py mà bạn gọi.

"Giới thiệu về Python" nói điều này về các tệp Python đã biên dịch:

Một chương trình không chạy nhanh hơn khi nó được đọc từ tệp '.pyc' hoặc '.pyo' so với khi nó được đọc từ tệp '.py'; điều duy nhất nhanh hơn về các tệp '.pyc' hoặc '.pyo' là tốc độ chúng được tải.

Ưu điểm của việc chạy tệp .pyc là Python không phải chịu chi phí biên dịch trước khi chạy tệp. Vì Python sẽ biên dịch thành mã byte trước khi chạy tệp .py, nên không có bất kỳ cải tiến hiệu suất nào ngoài điều đó.

Bạn có thể cải thiện được bao nhiêu từ việc sử dụng các tệp .pyc được biên dịch? Điều đó phụ thuộc vào những gì kịch bản làm. Đối với một kịch bản rất ngắn gọn chỉ đơn giản là in "Hello World", việc biên dịch có thể chiếm một tỷ lệ lớn trong tổng thời gian khởi động và chạy. Nhưng chi phí biên dịch một tập lệnh liên quan đến tổng thời gian chạy giảm dần cho các tập lệnh chạy dài hơn.

Tập lệnh bạn đặt tên trên dòng lệnh không bao giờ được lưu vào tệp .pyc. Chỉ các mô-đun được tải bởi tập lệnh "chính" đó được lưu theo cách đó.


3
Trong nhiều trường hợp thật khó để thấy sự khác biệt, nhưng tôi có một tệp python cụ thể với hơn 300.000 dòng. (Đó là một loạt các phép tính toán được tạo bởi một tập lệnh khác để kiểm tra) Phải mất 37 giây để biên dịch và chỉ có 2 giây để thực hiện.
wojtow

54

Điểm cộng:

Đầu tiên: nhẹ, thất bại obfuscation.

Thứ hai: nếu quá trình biên dịch dẫn đến một tệp nhỏ hơn đáng kể, bạn sẽ nhận được thời gian tải nhanh hơn. Đẹp cho web.

Thứ ba: Python có thể bỏ qua bước biên dịch. Nhanh hơn khi tải trọng. Đẹp cho CPU và web.

Thứ tư: bạn càng nhận xét nhiều, tệp .pychoặc .pyotệp sẽ càng nhỏ so với .pytệp nguồn .

Thứ năm: một người dùng cuối chỉ có một .pychoặc một .pyotập tin trong tay ít có khả năng đưa ra cho bạn một lỗi mà họ gây ra bởi một thay đổi không được hoàn nguyên mà họ quên nói với bạn.

Thứ sáu: nếu bạn đang nhắm đến một hệ thống nhúng, việc lấy một tệp có kích thước nhỏ hơn để nhúng có thể đại diện cho một điểm cộng đáng kể và kiến ​​trúc ổn định nên một nhược điểm, chi tiết dưới đây, không phát huy tác dụng.

Biên soạn cấp cao nhất

Thật hữu ích khi biết rằng bạn có thể biên dịch tệp nguồn python cấp cao nhất thành một .pyctệp theo cách này:

python -m py_compile myscript.py

Điều này loại bỏ ý kiến. Nó docstringscòn nguyên. Nếu bạn cũng muốn thoát khỏi điều đó docstrings(bạn có thể muốn nghiêm túc suy nghĩ về lý do tại sao bạn làm điều đó) thì hãy biên dịch theo cách này thay vì ...

python -OO -m py_compile myscript.py

... và bạn sẽ nhận được một .pyotệp thay vì một .pyctệp; phân phối đồng đều về chức năng thiết yếu của mã, nhưng nhỏ hơn bởi kích thước của phần bị loại bỏ docstrings(và ít dễ hiểu hơn cho việc làm tiếp theo nếu nó có vị trí tốt docstringsngay từ đầu). Nhưng xem nhược điểm ba, dưới đây.

Lưu ý rằng python sử dụng .pyngày của tập tin, nếu nó hiện diện, để quyết định liệu có nên thực hiện .pytập tin như trái ngược với .pychoặc .pyotập tin --- để chỉnh sửa tập tin py của bạn, và .pychoặc .pyolà lỗi thời và bất cứ điều gì có lợi cho bạn đạt được sẽ bị mất. Bạn cần biên dịch lại nó để lấy lại .pychoặc .pyolợi ích một lần nữa, chẳng hạn như chúng có thể.

Hạn chế:

Đầu tiên: Có một "cookie ma thuật" trong .pyc.pyocác tệp cho biết kiến ​​trúc hệ thống mà tệp python đã được biên dịch. Nếu bạn phân phối một trong các tệp này vào một môi trường thuộc loại khác, nó sẽ bị hỏng. Nếu bạn phân phối .pychoặc .pyokhông có liên kết .pyđể biên dịch lại hoặc touchdo đó, nó sẽ thay thế .pychoặc .pyo, người dùng cuối cũng không thể sửa nó.

Thứ hai: Nếu docstringsbị bỏ qua với việc sử dụng -OOtùy chọn dòng lệnh như được mô tả ở trên, không ai có thể nhận được thông tin đó, điều này có thể khiến việc sử dụng mã trở nên khó khăn hơn (hoặc không thể.)

Thứ ba: -OOTùy chọn của Python cũng thực hiện một số tối ưu hóa theo -Otùy chọn dòng lệnh; điều này có thể dẫn đến những thay đổi trong hoạt động. Tối ưu hóa được biết đến là:

  • sys.flags.optimize = 1
  • assert báo cáo bị bỏ qua
  • __debug__ = Sai

Thứ tư: nếu bạn cố tình làm cho tập lệnh python của bạn có thể thực thi được bằng thứ gì đó theo thứ tự #!/usr/bin/pythontrên dòng đầu tiên, thì tập tin này sẽ bị loại bỏ .pyc.pyocác tập tin và chức năng đó bị mất.

Thứ năm: hơi rõ ràng, nhưng nếu bạn biên dịch mã của mình, không chỉ việc sử dụng nó có thể bị ảnh hưởng mà khả năng người khác học hỏi từ công việc của bạn cũng bị giảm đi, thường là nghiêm trọng.


10

Có một sự gia tăng hiệu suất trong việc chạy python biên dịch. Tuy nhiên, khi bạn chạy tệp .py dưới dạng mô-đun đã nhập, python sẽ biên dịch và lưu trữ tệp, và miễn là tệp .py không thay đổi, nó sẽ luôn sử dụng phiên bản đã biên dịch.

Với bất kỳ ngôn ngữ xen kẽ nào khi tệp được sử dụng, quy trình sẽ trông giống như thế này:
1. Tệp được xử lý bởi trình thông dịch.
2. Tệp được biên dịch
3. Mã biên dịch được thực thi.

rõ ràng bằng cách sử dụng mã được biên dịch trước, bạn có thể loại bỏ bước 2, điều này áp dụng python, PHP và các mã khác.

Đây là một bài đăng blog thú vị giải thích sự khác biệt http://julipedia.blogspot.com/2004/07/compiled-vs-interprave-lacular.html
Và đây là một mục giải thích quá trình biên dịch Python http://effbot.org/zone /python-compile.htmlm


9

Như đã đề cập, bạn có thể tăng hiệu suất từ ​​việc mã python của bạn được biên dịch thành mã byte. Điều này thường được xử lý bởi chính python, chỉ cho các tập lệnh nhập khẩu.

Một lý do khác mà bạn có thể muốn biên dịch mã python của mình, có thể là để bảo vệ tài sản trí tuệ của bạn khỏi bị sao chép và / hoặc sửa đổi.

Bạn có thể đọc thêm về điều này trong tài liệu Python .


2
Liên quan đến việc bảo vệ mã của bạn - biên dịch sẽ không giúp được gì nhiều. Biên dịch obfuscates - nhưng ai đó có mong muốn sẽ nhận được mã của bạn bất kể.
Josh Smeaton

1
@josh luôn luôn có thể, nếu một người có thể truy cập vào bộ nhớ hoặc xem hướng dẫn về cpu, với đủ thời gian và họ có thể xây dựng lại ứng dụng của bạn không.
UnkwnTech

5
Đồng ý, tuy nhiên như Unkwntech đã nói, điều đó sẽ luôn luôn có thể, nếu người đó đủ quyết tâm. Nhưng tôi tin rằng nó sẽ đủ trong hầu hết các tình huống, nơi bạn thường chỉ muốn hạn chế mọi người "sửa" mã của mình ...
Simon B. Jensen

Ngôn ngữ được biên dịch để bytecode nói chung là không phải tất cả khó có thể đảo ngược-biên dịch , trừ khi bạn thực hiện các bước thêm để xáo trộn chúng - chỉ biên dịch thường sẽ không đủ.
EJoshuaS - Phục hồi Monica

7

Chắc chắn có sự khác biệt về hiệu năng khi chạy tập lệnh được biên dịch. Nếu bạn chạy .pycác tập lệnh bình thường , máy sẽ biên dịch nó mỗi khi nó chạy và điều này sẽ mất thời gian. Trên các máy hiện đại, điều này hầu như không đáng chú ý nhưng khi kịch bản phát triển, nó có thể trở thành một vấn đề.


7

Một cái gì đó không chạm vào là biên dịch nguồn-nguồn . Ví dụ, nuitkadịch mã Python sang C / C ++ và biên dịch mã thành mã nhị phân chạy trực tiếp trên CPU, thay vì mã byte Python chạy trên máy ảo chậm hơn.

Điều này có thể dẫn đến việc tăng tốc đáng kể hoặc nó sẽ cho phép bạn làm việc với Python trong khi môi trường của bạn phụ thuộc vào mã C / C ++.


4

Chúng tôi sử dụng mã được biên dịch để phân phối cho người dùng không có quyền truy cập vào mã nguồn. Về cơ bản để ngăn chặn các lập trình viên thiếu kinh nghiệm vô tình thay đổi một cái gì đó hoặc sửa lỗi mà không cho chúng tôi biết.


2

Đúng, hiệu suất là lý do chính và, theo như tôi biết, lý do duy nhất.

Nếu một số tệp của bạn không được biên dịch, có thể Python không thể ghi vào tệp .pyc, có lẽ vì quyền của thư mục hoặc thứ gì đó. Hoặc có lẽ các tệp chưa được biên dịch sẽ không được tải ... (tập lệnh / mô-đun chỉ được biên dịch khi chúng được tải lần đầu)


1

Người mới bắt đầu giả sử Python được biên dịch vì các tệp .pyc. Tệp .pyc là mã byte được biên dịch, sau đó được giải thích. Vì vậy, nếu bạn đã chạy mã Python của mình trước đó và có tệp .pyc tiện dụng, nó sẽ chạy nhanh hơn lần thứ hai, vì nó không phải biên dịch lại mã byte

trình biên dịch: Trình biên dịch là một đoạn mã dịch ngôn ngữ cấp cao sang ngôn ngữ máy

Thông dịch viên: Phiên dịch viên cũng chuyển đổi ngôn ngữ cấp cao thành tương đương nhị phân có thể đọc được bằng máy. Mỗi khi trình thông dịch nhận được mã ngôn ngữ cấp cao sẽ được thực thi, nó sẽ chuyển đổi mã thành mã trung gian trước khi chuyển đổi thành mã máy. Mỗi phần của mã được diễn giải và sau đó thực hiện riêng biệt theo một chuỗi và một lỗi được tìm thấy trong một phần của mã, nó sẽ dừng việc giải thích mã mà không dịch bộ mã tiếp theo.

Nguồn: http://www.toptal.com/python/why-are-there-so-many-pythons http://www.engineersgarage.com/contribution/difference-b between-compiler-and-interpreter


9
Định nghĩa của bạn về "trình biên dịch" là không chính xác. Một trình biên dịch chưa bao giờ được biên dịch thành mã máy. Một trình biên dịch chỉ đơn thuần là một dịch giả từ ngôn ngữ này sang ngôn ngữ khác. Đây là lý do tại sao chúng tôi nói rằng Python "biên dịch" thành mã byte, Coffeescript "biên dịch" thành Javascript, v.v.
Ricky Stewart
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.