5
Mới! Lưu câu hỏi hoặc câu trả lời và sắp xếp nội dung yêu thích của bạn. Tìm hiểu thêm.
Learn more.
Gần đây, Python 3.6 đã thêm gõ tĩnh như một cách để thực thi một số loại. Chức năng tương tự này tôi đã sử dụng để có được nó từ Cython, có được các chức năng được tối ưu hóa cao khi so sánh với Vanilla Python.
Câu hỏi của tôi sau đó là: Chúng ta cũng sẽ tăng hiệu suất đáng kể khi sử dụng gõ tĩnh Python mới? Ưu/nhược điểm của mỗi phương pháp?
Hỏi ngày 8 tháng 8 năm 2018 lúc 9:20Aug 8, 2018 at 9:20
0
Gõ tĩnh trong Python không biến nó thành ngôn ngữ lập trình được biên dịch. Do đó, hiệu suất khôn ngoan, bạn nên luôn luôn có được hiệu suất tốt hơn từ Cython [được biên dịch phải luôn luôn đánh bại diễn giải].
Mục đích chính của việc đánh máy tĩnh mới được thêm vào của Python là thực hiện kiểm tra loại theo cách liền mạch, Bys hy sinh một số triết lý của Python trên đường đi.
Tóm lại: Cython cho tốc độ, Python3.6 cho phương pháp giải thích/pythonic hơn.: Cython for speed, Python3.6 for interpreted/more pythonic approach.
Đã trả lời ngày 8 tháng 8 năm 2018 lúc 9:26Aug 8, 2018 at 9:26
1
Không có gõ tĩnh trong bất kỳ phiên bản hiện có của CPython, 3.7 trở lên.static typing in any existing version of CPython, 3.7 or earlier.
Sự hỗ trợ cho các chú thích loại tùy chọn trong CPython 3.6 [cũng được đặt lại đến 3.5] giúp các công cụ bên ngoài như máy phân tích mã tĩnh xác minh rằng các loại được sử dụng một cách nhất quán trong một chương trình.type annotations in CPython 3.6 [backported to 3.5 as well] helps the external tools such as static code analysers to verify that types are used consistently in a program.
Loại gợi ý không có tác động đến việc biên dịch hoặc thực thi mã byte.
Từ CPython 3.6 có gì mới:
Trái ngược với các khai báo biến trong các ngôn ngữ được đánh máy tĩnh, mục tiêu của cú pháp chú thích là cung cấp một cách dễ dàng để chỉ định siêu dữ liệu loại có cấu trúc cho các công cụ và thư viện của bên thứ ba thông qua cây cú pháp trừu tượng và thuộc tính chú thích.annotations attribute.
Lưu ý rằng tuy nhiên, cú pháp gợi ý loại có thể được sử dụng trong Cython để xác định các loại C [Cú pháp khai báo loại].
Đã trả lời ngày 8 tháng 8 năm 2018 lúc 9:27Aug 8, 2018 at 9:27
Oleh Rybalchenkooleh RybalchenkoOleh Rybalchenko
5,8683 Huy hiệu vàng20 Huy hiệu bạc35 Huy hiệu Đồng3 gold badges20 silver badges35 bronze badges
Phiên bản này của tài liệu này dành cho chi nhánh phát triển mới nhất và lớn nhất của Cython. Đối với phiên bản phát hành cuối cùng, xem tại đây.
Ghi chú
Trang này sử dụng hai biến thể cú pháp khác nhau:
Cú pháp cụ thể của Cython, được thiết kế để làm cho các khai báo loại ngắn gọn và dễ đọc từ góc độ C/C ++.
Cú pháp Python thuần túy cho phép khai báo loại Cython tĩnh trong mã python thuần túy, theo gợi ý loại PEP-484 và các chú thích biến PEP 526.pure Python code, following PEP-484 type hints and PEP 526 variable annotations.
Để sử dụng các loại dữ liệu C trong cú pháp Python, bạn cần nhập mô -đun
cython
đặc biệt trong mô -đun Python mà bạn muốn biên dịch, ví dụ:
Cython là một trình biên dịch Python. Điều này có nghĩa là nó có thể biên dịch mã python bình thường mà không thay đổi [với một vài ngoại lệ rõ ràng về một số tính năng ngôn ngữ chưa được hỗ trợ, xem các hạn chế của Cython]. Tuy nhiên, đối với mã quan trọng hiệu suất, thường rất hữu ích khi thêm các khai báo loại tĩnh, vì chúng sẽ cho phép Cython bước ra khỏi bản chất động của mã Python và tạo mã C đơn giản hơn và nhanh hơn - đôi khi nhanh hơn theo thứ tự cường độ.Cython limitations]. However, for performance critical code, it is often helpful to add static type declarations, as they will allow Cython to step out of the dynamic nature of the Python code and generate simpler and faster C code - sometimes faster by orders of magnitude.
Tuy nhiên, cần lưu ý rằng các khai báo loại có thể làm cho mã nguồn nhiều dòng hơn và do đó không thể đọc được. Do đó, không khuyến khích sử dụng chúng mà không có lý do chính đáng, chẳng hạn như nơi điểm chuẩn chứng minh rằng chúng thực sự làm cho mã nhanh hơn đáng kể trong phần quan trọng hiệu suất. Thông thường một vài loại ở đúng điểm đi một chặng đường dài.
Tất cả các loại C đều có sẵn cho các loại khai báo loại: các loại điểm số nguyên và nổi, số phức, cấu trúc, công đoàn và loại con trỏ. Cython có thể tự động chuyển đổi và chính xác giữa các loại về gán. Điều này cũng bao gồm các loại số nguyên kích thước tùy ý của Python, trong đó giá trị tràn khi chuyển đổi sang loại C sẽ tăng Python OverflowError
khi chạy. [Tuy nhiên, nó không kiểm tra tràn khi thực hiện số học.] Mã C được tạo sẽ xử lý các kích thước phụ thuộc nền tảng của các loại C một cách chính xác và an toàn trong trường hợp này.
Các loại được khai báo thông qua từ khóa CDEF.
Gõ các biến
Hãy xem xét mã Python thuần túy sau:
Tích hợp.py¶¶
def f[x]: return x ** 2 - x def integrate_f[a, b, N]: s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx
Đơn giản chỉ cần biên dịch điều này ở Cython chỉ đơn thuần là tăng tốc 35%. Điều này tốt hơn là không có gì, nhưng thêm một số loại tĩnh có thể tạo ra sự khác biệt lớn hơn nhiều.
Với các khai báo loại bổ sung, điều này có thể trông giống như:
Tích hợp_cy.py¶¶
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx
Do biến Iterator i
được gõ bằng chữ C, nên vòng lặp sẽ được biên dịch thành mã C thuần túy. Gõ a
, s
và dx
rất quan trọng vì chúng có liên quan đến số học trong vòng lặp; Gõ
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx0 và
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx1 làm cho ít sự khác biệt hơn, nhưng trong trường hợp này, nó không có nhiều công việc để nhất quán và gõ toàn bộ chức năng.
Điều này dẫn đến tăng tốc 4 lần so với phiên bản Python thuần túy.
Chức năng gõ
Các cuộc gọi chức năng Python có thể tốn kém - trong Cython gấp đôi vì vậy người ta có thể cần phải chuyển đổi đến và từ các đối tượng Python để thực hiện cuộc gọi. Trong ví dụ của chúng tôi ở trên, đối số được coi là một c gấp đôi cả bên trong
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx2 và trong cuộc gọi đến nó, nhưng một đối tượng Python
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx3 phải được xây dựng xung quanh đối số để vượt qua nó.
Do đó, Cython cung cấp một cách để khai báo chức năng kiểu C, tuyên bố cụ thể của Cython, cũng như trình trang trí
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx5 để khai báo các chức năng kiểu C trong cú pháp Python. Cả hai cách tiếp cận đều tương đương và tạo ra cùng một mã C:
@cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x
Một số hình thức của bộ biến đổi ngoại trừ thường nên được thêm vào, nếu không, Cython sẽ không thể tuyên truyền các ngoại lệ được nêu trong hàm [hoặc một hàm mà nó gọi].
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx6 có nghĩa là một lỗi sẽ được kiểm tra nếu
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx7 được trả về [mặc dù
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx8 chỉ ra rằng
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx7 cũng có thể được sử dụng làm giá trị trả về hợp lệ]. Điều tương tự có thể được thể hiện chỉ bằng cách sử dụng cú pháp Python với bộ trang trí
@cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x0.
Ngoài ra,
@cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x1 chậm hơn luôn an toàn. Một mệnh đề ngoại trừ có thể bị bỏ lại nếu hàm trả về một đối tượng Python hoặc nếu nó được đảm bảo rằng một ngoại lệ sẽ không được nêu trong cuộc gọi chức năng. Một lần nữa, Cython cung cấp cho người trang trí
@cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x2 cung cấp chức năng tương tự.
Một tác dụng phụ của cdef
[và người trang trí
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx5] là chức năng không còn được nhìn thấy từ không gian Python, như Python sẽ không biết cách gọi nó. Cũng không còn có thể thay đổi
def f[x: cython.double]: return x ** 2 - x def integrate_f[a: cython.double, b: cython.double, N: cython.int]: i: cython.int s: cython.double dx: cython.double s = 0 dx = [b - a] / N for i in range[N]: s += f[a + i * dx] return s * dx2 khi chạy.
Sử dụng từ khóa
@cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x6 thay vì
cdef
, trình bao bọc Python cũng được tạo, để hàm có sẵn cả từ Cython [nhanh, truyền trực tiếp các giá trị được đánh máy] và từ Python [kết thúc các giá trị trong các đối tượng Python]. Trên thực tế, @cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x6 không chỉ cung cấp trình bao bọc Python, nó còn cài đặt logic để cho phép phương thức được ghi đè bởi các phương thức Python, ngay cả khi được gọi từ bên trong Cython. Điều này không thêm một chi phí nhỏ so với các phương pháp
cdef
. Một lần nữa, Cython cung cấp một trình trang trí cdef
0 cung cấp chức năng tương tự như từ khóa @cython.cfunc @cython.exceptval[-2, check=True] def f[x: cython.double] -> cython.double: return x ** 2 - x6.
Tăng tốc: 150 lần so với Python thuần túy.
Xác định nơi để thêm các loại
Bởi vì gõ tĩnh thường là chìa khóa để tăng tốc độ lớn, người mới bắt đầu thường có xu hướng gõ mọi thứ trong tầm nhìn. Điều này cắt giảm cả khả năng đọc và tính linh hoạt, và thậm chí có thể làm chậm mọi thứ [ví dụ: bằng cách thêm kiểm tra loại không cần thiết, chuyển đổi hoặc giải nén bộ đệm chậm]. Mặt khác, thật dễ dàng để tiêu diệt hiệu suất bằng cách quên gõ một biến vòng lặp quan trọng. Hai công cụ cần thiết để giúp với nhiệm vụ này là hồ sơ và chú thích. Hồ sơ phải là bước đầu tiên của bất kỳ nỗ lực tối ưu hóa nào và có thể cho bạn biết bạn đang dành thời gian ở đâu. Chú thích của Cython sau đó có thể cho bạn biết lý do tại sao mã của bạn mất thời gian.
Sử dụng chuyển đổi cdef
2 sang chương trình dòng lệnh cython
[hoặc theo liên kết từ SAGE Notebook] dẫn đến báo cáo HTML về mã Cython xen kẽ với mã C được tạo. Các dòng được tô màu theo mức độ của sự đánh máy của người Hồi giáo-các dòng màu trắng chuyển thành C thuần khiết, trong khi các dòng yêu cầu Python C-API có màu vàng [tối hơn khi chúng chuyển sang tương tác C-API nhiều hơn]. Các dòng dịch sang mã C có điểm cộng [cdef
4] ở phía trước và có thể được nhấp để hiển thị mã được tạo.
Báo cáo này là vô giá khi tối ưu hóa một hàm cho tốc độ và để xác định khi nào nên phát hành GIL: Nói chung, một khối cdef
5 có thể chỉ chứa mã trắng của Hồi.release the GIL: in general, a cdef
5 block may contain only “white” code.
Lưu ý rằng Cython suy ra loại biến cục bộ dựa trên các bài tập của chúng [bao gồm cả mục tiêu biến vòng lặp] cũng có thể cắt giảm nhu cầu chỉ định rõ ràng các loại ở mọi nơi. Ví dụ: tuyên bố dx
là loại gấp đôi ở trên là không cần thiết, như là tuyên bố loại s
trong phiên bản cuối cùng [trong đó loại trả về của cdef
8 được biết là một c Double.] Được sử dụng trong các biểu thức số học, vì Cython không thể đảm bảo rằng một luồng tràn sẽ không xảy ra [và do đó rơi trở lại cdef
9 trong trường hợp Bignums của Python là cần thiết]. Để cho phép suy luận của các loại số nguyên C, hãy đặt lệnh cython
0 thành cython
1. Chỉ thị này thực hiện một công việc tương tự như từ khóa cython
2 trong C ++ cho những người đọc quen thuộc với tính năng ngôn ngữ này. Nó có thể giúp đỡ rất nhiều để cắt giảm nhu cầu gõ mọi thứ, nhưng nó cũng có thể dẫn đến những bất ngờ. Đặc biệt nếu một người không quen thuộc với các biểu thức số học với các loại C. Một cái nhìn tổng quan nhanh về những người có thể được tìm thấy ở đây.directive to
cython
1. This directive does a work similar to the cython
2 keyword in C++ for the readers who are familiar with this language feature. It can be of great help to cut down on the need to type everything, but it also can lead to surprises. Especially if one isn’t familiar with arithmetic expressions with c types. A quick overview of those can be found here.