Hướng dẫn can cython compile all python code? - cython có thể biên dịch tất cả mã python không?

Trái ngược với những gì Adam Matan và những người khác khẳng định, trên thực tế, bạn có thể tạo một tệp nhị phân thực thi duy nhất bằng Cython, từ tệp Python (.py) thuần túy.can in fact create a single executable binary file using Cython, from a pure Python (.py) file.

Có, Cython được dự định sẽ được sử dụng như đã nêu - như một cách đơn giản hóa việc viết các mô -đun mở rộng C/C ++ cho thời gian chạy Cpython Python.

Nhưng, như Nudzo ám chỉ trong nhận xét này, bạn có thể sử dụng công tắc

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
9 tại dấu nhắc dòng lệnh.

Đây là một ví dụ cực kỳ đơn giản. Tôi đang thực hiện điều này từ một máy trạm SID Debian, sử dụng Python3 và Cython3 ..

Hãy chắc chắn rằng bạn đã cài đặt các gói Python-Dev hoặc Python3-Dev trước.python-dev or python3-dev packages installed beforehand.

1) Tạo một chương trình Python rất đơn giản có tên là Hello.py Create a very simple Python program called hello.py

$ cat hello.py

In ("Hello World!")

2) Sử dụng Cython để biên dịch chương trình Python của bạn thành C ... Use Cython to compile your python program into C...

cython3 --embed -o hello.c hello.py

3) Sử dụng GCC để biên dịch Hello.c vào tệp thực thi có tên là Hello ... Use GCC to compile hello.c into an executable file called hello...

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl

4) Bạn kết thúc với một tệp có tên là Hello ... You end up with a file called hello ...

$ File Xin chào

Xin chào: ELF 64-bit LSB thực thi, x86-64, phiên bản 1 (SYSV), liên kết động (sử dụng LIBS được chia sẻ), cho GNU/Linux 2.6.32, BuildID [SHA1] = 006F45195A26F1949C6

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)

Trong trường hợp này, thực thi có thể được liên kết động với Python 3.3 trên hệ thống Debian của tôi.

5) Chạy xin chào ... run hello...

$ ./hello

Chào thế giới!

Như bạn có thể thấy, sử dụng phương pháp này, về cơ bản, bạn có thể sử dụng Cython để chuyển đổi các ứng dụng Python thuần túy của bạn thành mã đối tượng được biên dịch, có thể thực thi.

Tôi đang sử dụng phương pháp này cho các ứng dụng phức tạp hơn rất nhiều - ví dụ: ứng dụng Python/pyside/QT bị thổi đầy đủ.

Đối với các phiên bản khác nhau của Python, bạn điều chỉnh các chuyển đổi GCC

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
0 và
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
1 cho phù hợp.
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
0
and
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
1
switches to suit.

Sau đó, bạn có thể đóng gói tệp thực thi dưới dạng phân phối (.deb, v.v.) Phiên bản của Python, vv trên phân phối đó.

Những điều cơ bản của Cython¶

Bản chất cơ bản của Cython có thể được tóm tắt như sau: Cython là Python với các loại dữ liệu C.

Cython là Python: Hầu như bất kỳ đoạn mã Python nào cũng là mã Cython hợp lệ. .Limitations, but this approximation will serve for now.) The Cython compiler will convert it into C code which makes equivalent calls to the Python/C API.

Nhưng Cython còn nhiều hơn thế, bởi vì các tham số và biến có thể được khai báo là có các loại dữ liệu C. Mã thao túng các giá trị python và giá trị C có thể được xen kẽ tự do, với các chuyển đổi xảy ra tự động bất cứ khi nào có thể. Bảo trì số lượng tham chiếu và kiểm tra lỗi của các hoạt động Python cũng là tự động và toàn bộ sức mạnh của các cơ sở xử lý ngoại lệ Python, bao gồm các câu lệnh Try-Except và Try-Finally, có sẵn cho bạn-ngay cả khi thao túng dữ liệu C.Python values and C values can be freely intermixed, with conversions occurring automatically wherever possible. Reference count maintenance and error checking of Python operations is also automatic, and the full power of Python’s exception handling facilities, including the try-except and try-finally statements, is available to you – even in the midst of manipulating C data.

Cython Hello World¶

Vì Cython có thể chấp nhận hầu hết mọi tệp nguồn Python hợp lệ, một trong những điều khó khăn nhất khi bắt đầu chỉ là tìm ra cách biên dịch tiện ích mở rộng của bạn.

Vì vậy, hãy bắt đầu với The Canonical Python Hello World:

Lưu mã này trong một tệp có tên

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
2. Bây giờ chúng ta cần tạo
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3, giống như một makefile python (để biết thêm thông tin, hãy xem các tệp và biên dịch nguồn).
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3 của bạn sẽ trông giống như:Source Files and Compilation). Your
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3 should look like:

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)

Để sử dụng điều này để xây dựng tệp Cython của bạn, hãy sử dụng các tùy chọn dòng lệnh:

$ python setup.py build_ext --inplace

Sẽ để lại một tệp trong thư mục cục bộ của bạn có tên

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
5 trong Unix hoặc
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
6 trong Windows. Bây giờ để sử dụng tệp này: Bắt đầu trình thông dịch Python và chỉ cần nhập nó như thể đó là mô -đun Python thông thường:

>>> import helloworld
Hello World

Xin chúc mừng! Bây giờ bạn biết cách xây dựng một phần mở rộng Cython. Nhưng cho đến nay, ví dụ này không thực sự mang lại cảm giác tại sao người ta muốn sử dụng Cython, vì vậy hãy tạo ra một ví dụ thực tế hơn.

from setuptools import setup from Cython.Build import cythonize setup( ext_modules = cythonize("helloworld.pyx") ) 7: biên soạn Cython cho các nhà phát triển

Nếu mô -đun của bạn không yêu cầu bất kỳ thư viện C bổ sung nào hoặc thiết lập bản dựng đặc biệt, thì bạn có thể sử dụng mô -đun pyimimport, ban đầu được phát triển bởi Paul Prescod, để tải các tệp .pyx trực tiếp khi nhập mà không phải chạy tệp

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3 của bạn mỗi khi bạn Thay đổi mã của bạn. Nó được vận chuyển và cài đặt với Cython và có thể được sử dụng như thế này:

>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World

Mô -đun Pyximport cũng có hỗ trợ biên dịch thử nghiệm cho các mô -đun Python bình thường. Điều này cho phép bạn tự động chạy Cython trên mọi mô -đun .pyx và .py mà Python nhập, bao gồm thư viện tiêu chuẩn và các gói được cài đặt. Cython vẫn sẽ không biên dịch rất nhiều mô -đun Python, trong trường hợp đó, cơ chế nhập sẽ quay trở lại để tải các mô -đun nguồn Python thay thế. Cơ chế nhập .Py được cài đặt như thế này:Pyximport module also has experimental compilation support for normal Python modules. This allows you to automatically run Cython on every .pyx and .py module that Python imports, including the standard library and installed packages. Cython will still fail to compile a lot of Python modules, in which case the import mechanism will fall back to loading the Python source modules instead. The .py import mechanism is installed like this:

>>> pyximport.install(pyimport=True)

Lưu ý rằng không nên để cho mã xây dựng PyMimport ở phía người dùng cuối khi nó nối vào hệ thống nhập của họ. Cách tốt nhất để phục vụ cho người dùng cuối là cung cấp các gói nhị phân được xây dựng trước ở định dạng bao bì bánh xe.Pyximport build code on end user side as it hooks into their import system. The best way to cater for end users is to provide pre-built binary packages in the wheel packaging format.

Fibonacci vui vẻ

Từ hướng dẫn Python chính thức, một hàm Fibonacci đơn giản được định nghĩa là:

from __future__ import print_function

def fib(n):
    """Print the Fibonacci series up to n."""
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a + b

    print()

Bây giờ làm theo các bước cho ví dụ Hello World, trước tiên chúng tôi đổi tên tệp để có phần mở rộng .pyx, hãy nói

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
9, sau đó chúng tôi tạo tệp
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3. Sử dụng tệp được tạo cho ví dụ Hello World, tất cả những gì bạn cần thay đổi là tên của tên tệp Cython và tên mô -đun kết quả, làm điều này chúng tôi có:

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules=cythonize("fib.pyx"),
)

Xây dựng phần mở rộng với cùng một lệnh được sử dụng cho Helloworld.pyx:

$ python setup.py build_ext --inplace

Và sử dụng tiện ích mở rộng mới với:

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
1

Người có giá.

Ở đây, một ví dụ nhỏ cho thấy một số điều có thể được thực hiện. Nó là một thói quen để tìm số nguyên tố. Bạn nói với nó có bao nhiêu số nguyên tố bạn muốn, và nó trả lại chúng như một danh sách Python.

Primes.py¶

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
2

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
3

Bạn có thể thấy rằng nó bắt đầu giống như một định nghĩa hàm Python bình thường, ngoại trừ tham số

$ python setup.py build_ext --inplace
1 được tuyên bố là loại
$ python setup.py build_ext --inplace
2. Điều này có nghĩa là đối tượng được truyền sẽ được chuyển đổi thành số nguyên C (hoặc
$ python setup.py build_ext --inplace
3 sẽ được nâng lên nếu nó có thể được).

Bây giờ, hãy để đào sâu vào lõi của chức năng:

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
4

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
5

Dòng 2, 3, 11 và 12 Sử dụng các chú thích biến để xác định một số biến C cục bộ. Kết quả được lưu trữ trong mảng C

$ python setup.py build_ext --inplace
4 trong quá trình xử lý và sẽ được sao chép vào danh sách python ở cuối (dòng 26).

Ghi chú

Bạn không thể tạo ra các mảng rất lớn theo cách này, bởi vì chúng được phân bổ trên ngăn xếp gọi hàm C, đây là một tài nguyên khá quý giá và khan hiếm. Để yêu cầu các mảng lớn hơn hoặc thậm chí các mảng có độ dài chỉ được biết trong thời gian chạy, bạn có thể tìm hiểu cách sử dụng hiệu quả phân bổ bộ nhớ C, mảng python hoặc mảng numpy với Cython.stack, which is a rather precious and scarce resource. To request larger arrays, or even arrays with a length only known at runtime, you can learn how to make efficient use of C memory allocation, Python arrays or NumPy arrays with Cython.

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
6

Như trong C, khai báo một mảng tĩnh yêu cầu biết kích thước tại thời điểm biên dịch. Chúng tôi đảm bảo người dùng không đặt giá trị trên 1000 (hoặc chúng tôi sẽ có lỗi phân đoạn, giống như trong C)

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
7

Khi chúng tôi chạy mã này từ Python, chúng tôi phải khởi tạo các mục trong mảng. Điều này dễ dàng được thực hiện nhất bằng cách điền vào nó bằng các số không (như đã thấy trên dòng 8-9). Khi chúng ta biên dịch nó với Cython, mặt khác, mảng sẽ hoạt động như trong C. Nó được phân bổ trên ngăn xếp gọi hàm với độ dài cố định là 1000 mục có chứa dữ liệu tùy ý từ lần cuối cùng bộ nhớ được sử dụng. Sau đó chúng tôi sẽ ghi đè lên những mục đó trong tính toán của chúng tôi.

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
8

Các dòng 11-13 thiết lập một vòng lặp trong thời gian sẽ kiểm tra các số ứng dụng thành số nguyên tố cho đến khi số lượng số nguyên tố cần thiết được tìm thấy.

gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl
9

Các dòng 15-16, cố gắng chia một ứng cử viên cho tất cả các số nguyên tố được tìm thấy cho đến nay, được đặc biệt quan tâm. Bởi vì không có đối tượng Python nào được đề cập, vòng lặp được dịch hoàn toàn thành mã C và do đó chạy rất nhanh. Bạn sẽ nhận thấy cách chúng tôi lặp lại trên mảng

$ python setup.py build_ext --inplace
4 C.

Vòng lặp được dịch thành một vòng lặp nhanh và hoạt động giống như lặp lại trong danh sách trăn hoặc mảng numpy. Nếu bạn không cắt lát mảng C với

$ python setup.py build_ext --inplace
6, thì Cython sẽ lặp qua 1000 phần tử của mảng.

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
0

Nếu không có sự phá vỡ xảy ra, điều đó có nghĩa là chúng tôi đã tìm thấy một số nguyên tố và khối mã sau dòng

$ python setup.py build_ext --inplace
7 20 sẽ được thực thi. Chúng tôi thêm các nguyên tố được tìm thấy vào
$ python setup.py build_ext --inplace
4. Nếu bạn thấy có một
$ python setup.py build_ext --inplace
7 sau khi một vòng lặp xa lạ, chỉ cần biết rằng đó là một tính năng ít được biết đến của ngôn ngữ Python và Cython thực hiện nó với tốc độ C cho bạn. Nếu cú ​​pháp For-Else làm bạn bối rối, hãy xem bài đăng trên blog tuyệt vời này.

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
1

Trong dòng 26, trước khi trả lại kết quả, chúng ta cần sao chép mảng C của mình vào danh sách Python, bởi vì Python có thể đọc các mảng C. Cython có thể tự động chuyển đổi nhiều loại C từ và thành các loại Python, như được mô tả trong tài liệu về chuyển đổi loại, vì vậy chúng ta có thể sử dụng một danh sách đơn giản ở đây để sao chép các giá trị C

$ python setup.py build_ext --inplace
2 thành danh sách Python của Python
$ python setup.py build_ext --inplace
2 đối tượng, mà Cython tạo tự động tạo dọc đường. Bạn cũng có thể lặp lại bằng tay trên mảng C và sử dụng
>>> import helloworld
Hello World
2, kết quả sẽ giống nhau.type conversion, so we can use a simple list comprehension here to copy the C
$ python setup.py build_ext --inplace
2 values into a Python list of Python
$ python setup.py build_ext --inplace
2 objects, which Cython creates automatically along the way. You could also have iterated manually over the C array and used
>>> import helloworld
Hello World
2, the result would have been the same.

Bạn có thể nhận thấy chúng tôi tuyên bố một danh sách Python chính xác giống như cách nó sẽ có trong Python. Bởi vì biến

>>> import helloworld
Hello World
3 đã được khai báo rõ ràng với một loại, nên nó được cho là giữ một đối tượng Python và từ bài tập, Cython cũng biết rằng loại chính xác là danh sách Python.

Cuối cùng, ở dòng 27, câu lệnh Python Return bình thường trả về danh sách kết quả.

Biên dịch Primes.py với trình biên dịch Cython tạo ra một mô -đun mở rộng mà chúng ta có thể thử trong trình thông dịch tương tác như sau:

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
2

Thấy chưa, nó hoạt động! Và nếu bạn tò mò về việc Cython đã cứu bạn bao nhiêu công việc, hãy xem mã C được tạo ra cho mô -đun này.

Cython có một cách để hình dung nơi mà sự tương tác với các đối tượng Python và Python xông C-API đang diễn ra. Đối với điều này, chuyển tham số

>>> import helloworld
Hello World
4 sang
>>> import helloworld
Hello World
5. Nó tạo ra một tập tin HTML. Hãy xem nào:

Hướng dẫn can cython compile all python code? - cython có thể biên dịch tất cả mã python không?

Nếu một dòng có màu trắng, điều đó có nghĩa là mã được tạo ra không tương tác với Python, do đó sẽ chạy nhanh như mã C bình thường. Vàng càng tối, tương tác Python càng có nhiều trong dòng đó. Những đường màu vàng này thường sẽ hoạt động trên các đối tượng Python, nâng cao ngoại lệ hoặc thực hiện các loại hoạt động cấp cao hơn so với những gì có thể dễ dàng được dịch thành mã C đơn giản và nhanh chóng. Tuyên bố chức năng và trả lại Sử dụng trình thông dịch Python để có ý nghĩa cho các dòng đó có màu vàng. Tương tự đối với danh sách hiểu vì nó liên quan đến việc tạo ra một đối tượng Python. Nhưng dòng

>>> import helloworld
Hello World
6, tại sao? Chúng ta có thể kiểm tra mã C được tạo để hiểu:

Hướng dẫn can cython compile all python code? - cython có thể biên dịch tất cả mã python không?

Chúng ta có thể thấy rằng một số kiểm tra xảy ra. Bởi vì Cython mặc định là hành vi của Python, ngôn ngữ sẽ thực hiện kiểm tra phân chia trong thời gian chạy, giống như Python. Bạn có thể hủy kích hoạt các kiểm tra đó bằng cách sử dụng các chỉ thị trình biên dịch.compiler directives.

Bây giờ, hãy để xem nếu chúng ta tăng tốc độ ngay cả khi có kiểm tra phân chia. Hãy để viết cùng một chương trình, nhưng trong Python:

Primes_python.py / primes_python_compiled.py¶

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
3

Có thể lấy một tệp đơn giản (không được bảo vệ)

>>> import helloworld
Hello World
7 và biên dịch nó với Cython. Hãy để tạo ra một bản sao của
>>> import helloworld
Hello World
8 và đặt tên cho nó
>>> import helloworld
Hello World
9 để có thể so sánh nó với mô-đun Python (không biên dịch). Sau đó, chúng tôi biên dịch tệp đó với Cython, mà không thay đổi mã. Bây giờ
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3 trông như thế này:

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
4

Bây giờ chúng tôi có thể đảm bảo rằng hai chương trình đó xuất ra cùng một giá trị:

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
5

Nó có thể so sánh tốc độ ngay bây giờ:

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
6

Phiên bản cythonize của

>>> import helloworld
Hello World
8 nhanh hơn 2 lần so với python, mà không thay đổi một dòng mã. Phiên bản Cython nhanh hơn 13 lần so với phiên bản Python! Điều gì có thể giải thích điều này?

Nhiều điều:
  • Trong chương trình này, rất ít tính toán xảy ra ở mỗi dòng. Vì vậy, chi phí của thông dịch viên Python là rất quan trọng. Sẽ rất khác nếu bạn thực hiện nhiều tính toán ở mỗi dòng. Sử dụng Numpy chẳng hạn.

  • Địa phương dữ liệu. Nó có khả năng rất nhiều có thể phù hợp với bộ đệm CPU khi sử dụng C so với khi sử dụng Python. Bởi vì mọi thứ trong Python là một đối tượng và mọi đối tượng được thực hiện như một từ điển, điều này không thân thiện với bộ nhớ cache.

Thông thường các tốc độ tăng tốc từ 2x đến 1000x. Nó phụ thuộc vào số tiền bạn gọi là phiên dịch Python. Như mọi khi, hãy nhớ hồ sơ trước khi thêm các loại ở mọi nơi. Thêm loại làm cho mã của bạn không thể đọc được, vì vậy hãy sử dụng chúng với mức độ kiểm duyệt.

Số nguyên tố với C ++ ¶

Với Cython, cũng có thể tận dụng ngôn ngữ C ++, một phần của thư viện tiêu chuẩn C ++ có thể nhập trực tiếp từ mã Cython.

Hãy cùng xem mã của chúng tôi trở thành gì khi sử dụng vectơ từ thư viện tiêu chuẩn C ++.

Ghi chú

Vector trong C ++ là một cấu trúc dữ liệu thực hiện danh sách hoặc ngăn xếp dựa trên mảng C có thể thay thế. Nó tương tự như loại Python

>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
2 trong mô -đun thư viện tiêu chuẩn
>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
2. Có một dự trữ phương thức có sẵn sẽ tránh các bản sao nếu bạn biết trước có bao nhiêu yếu tố bạn sẽ đặt trong vector. Để biết thêm chi tiết, hãy xem trang này từ CPPReference.

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
7

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)
8

Cảnh báo

Mã được cung cấp ở trên / trên trang này sử dụng thư viện gốc bên ngoài (không python) thông qua

>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
4 (
>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
5). Việc biên dịch Cython cho phép điều này, nhưng không có hỗ trợ cho điều này từ Python đơn giản. Cố gắng chạy mã này từ Python (không có tổng hợp) sẽ thất bại khi truy cập thư viện bên ngoài. Điều này được mô tả chi tiết hơn trong việc gọi các chức năng C.Calling C functions.

Dòng đầu tiên là một chỉ thị trình biên dịch. Nó bảo Cython biên dịch mã của bạn thành C ++. Điều này sẽ cho phép sử dụng các tính năng ngôn ngữ C ++ và thư viện tiêu chuẩn C ++. Lưu ý rằng không thể biên dịch mã Cython thành C ++ với pyimimport. Bạn nên sử dụng

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)
3 hoặc máy tính xách tay để chạy ví dụ này.

Bạn có thể thấy rằng API của một vectơ tương tự như API của danh sách Python và đôi khi có thể được sử dụng như một sự thay thế thả vào ở Cython.

Để biết thêm chi tiết về việc sử dụng C ++ với Cython, hãy xem bằng C ++ trong Cython.Using C++ in Cython.

Chi tiết ngôn ngữ

Để biết thêm về ngôn ngữ Cython, hãy xem các vấn đề cơ bản về ngôn ngữ. Để đi sâu vào việc sử dụng Cython trong bối cảnh tính toán số, hãy xem MemoryView được gõ.Language Basics. To dive right in to using Cython in a numerical computation context, see Typed Memoryviews.

Cython có tương thích với Python không?

Cython được viết bằng Python và C và hoạt động trên Windows, MacOS và Linux, sản xuất các tệp nguồn tương thích với các phiên bản CPython 2.6, 2.7 và 3.3 trở lên. and works on Windows, macOS, and Linux, producing source files compatible with CPython 2.6, 2.7, and 3.3 and later versions.

Cython có tốt hơn Python không?

Hiệu suất và tốc độ mặc dù là một siêu sao của Python, Cython nhanh hơn nhiều so với Python.Nó cải thiện tốc độ thực thi mã Python đáng kể bằng cách biên dịch mã python vào mã C.Việc biên dịch tiếp tục giúp các nhà phát triển chạy các chương trình Python một cách trơn tru mà không cần triển khai các tài nguyên điện toán bổ sung.Cython is much faster than Python. It improves Python code execution speed significantly by compiling Python code into C code. The compilation further helps developers to run the Python programs smoothly without deploying additional computing resources.

Cython nhanh hơn Python nhanh hơn bao nhiêu?

Lưu ý rằng Python thông thường mất hơn 500 giây để thực thi mã trên trong khi Cython chỉ mất khoảng 1 giây.Do đó, Cython nhanh hơn 500 lần so với Python để tổng số 1 tỷ con số.500x times faster than Python for summing 1 billion numbers.

Cython khác với Python khác nhau như thế nào?

Python là một ngôn ngữ lập trình được giải thích.Do đó, các lập trình viên Python cần thông dịch viên để chuyển đổi mã python thành mã máy.Trong khi Cython là một ngôn ngữ lập trình được biên dịch.Các chương trình Cython có thể được thực hiện trực tiếp bởi CPU của máy tính cơ bản mà không cần sử dụng bất kỳ trình thông dịch nào.Cython is a compiled programming language. The Cython programs can be executed directly by the CPU of the underlying computer without using any interpreter.