Cách tích hợp c và python

Python là một ngôn ngữ tuyệt vời, rất dễ tiếp thu, phát triển rất nhanh và rất rõ ràng để đọc. Tất cả những lợi ích này đều phải trả giá. Python khá chậm so với một số ngôn ngữ khác. Tôi thực sự khuyên bạn nên đọc bài viết này trước khi tiếp tục hiểu rõ vấn đề mà chúng tôi đang cố gắng giải quyết. Mục tiêu của bài viết này là để trả lời câu hỏi này

Làm cách nào chúng ta có thể kết hợp tính dễ phát triển của Python mà không làm giảm tốc độ?

Câu trả lời mỉa mai là viết lại dự án bằng ngôn ngữ khác nhưng đó không phải là mục đích chúng tôi ở đây. Bạn là một lập trình viên Python, đã có rất nhiều chương trình viết bằng Python và chỉ muốn tăng tốc một phần nhỏ của nó. Cũng. nếu bạn đã quen viết bằng Python, việc chuyển đổi sang ngôn ngữ khác như C# hoặc Java có thể khá khó khăn

Chúng tôi sẽ kết hợp tốt nhất của hai thế giới. chúng tôi mở rộng chương trình của mình bằng một mô-đun nhỏ mà chúng tôi viết bằng C. Các lập trình viên Python chỉ cần nhập gói này, không cần biết một dòng C nào và vẫn có thể tận hưởng tốc độ tăng gấp 100 lần

Nhập mô-đun C vào chương trình Python của chúng tôi (hình ảnh của (Kat Sazonova trên Bapt)

Viết bằng C?

“Viết bằng chữ C. ?”

“Bạn vừa nói về một quá trình chuyển đổi sơ bộ sang Java, giờ chúng ta sẽ chuyển sang C?. ”. Đúng, viết mã bằng C có thể hơi khó khăn nhưng bạn sẽ thấy tốc độ tăng gấp 100 lần hoàn toàn xứng đáng

Ngoài ra, chúng tôi chỉ phải viết lại một phần nhỏ mã của mình sang C (trong trường hợp của chúng tôi chỉ là một hàm duy nhất)

Điều này không giống như viết lại dự án bằng ngôn ngữ khác sao?

Cái hay của giải pháp mà bài viết này mô tả là bạn chỉ phải viết lại những phần chậm trong mã của mình. Hãy tưởng tượng chúng ta đã lập trình một API bằng Python để nhận và phân tích các tệp âm thanh. Nên viết lại hàm phân tích tệp âm thanh trong C vì đây là nút cổ chai của dự án. Chúng tôi sẽ lãng phí rất nhiều thời gian để viết lại API của mình

Điều này không thể được thực hiện đơn giản hơn?

Vâng, có nhiều cách đơn giản hơn để tạo tiện ích mở rộng C sẽ tăng tốc chương trình của chúng tôi rất nhiều. Trong bài viết này, chúng tôi đã sử dụng Cython để chuyển đổi một số mã giống như Python thành mô-đun C để đạt được mức tăng hiệu suất gần như tương tự

Tuy nhiên, trong bài đăng này, chúng tôi sẽ thực hiện một cách khó khăn và viết mô-đun của riêng mình bằng C vì nó cho chúng tôi cái nhìn rất thú vị về hoạt động bên trong của Python và cách nó tích hợp các mô-đun được viết bằng C

Khi nào thì tạo một mô-đun C là hợp lý?

Loại tác vụ mà chúng tôi có thể tối ưu hóa là tác vụ nặng về CPU, không phải tác vụ I/O như chờ phản hồi. Chờ API không nhanh hơn trong 'ngôn ngữ nhanh hơn'

Chúng tôi muốn tối ưu hóa một phần nhỏ mã của chúng tôi để thực hiện một tác vụ rất nặng về CPU. Những loại tác vụ này rất phù hợp để tối ưu hóa trong C

Hãy thiết lập cửa hàng và tăng tốc chương trình này (hình ảnh của Damir Kopezhanov trên Bapt)Thiết lập

điều đầu tiên đầu tiên. thiết lập môi trường ảo. Điều này không thực sự cần thiết nhưng đó là cách tốt nhất để giữ cho các phần phụ thuộc của bạn không bị rối

Như bạn đã đọc ở phần trước, chúng ta sẽ cần một hàm tính toán nhiều. Chúng tôi sẽ sử dụng một ví dụ đơn giản. tính số lượng các số nguyên tố trong một phạm vi. Đây là mã Python vanilla sẽ làm điều đó

Đoạn mã trên trông hơi lộn xộn và tôi nghe bạn nghĩ “WHILE LOOPS?. CỜ?. ”. Tin tôi đi, họ ở đó vì một lý do chính đáng

Cũng lưu ý rằng đây không phải là cách hiệu quả nhất để tính số nguyên tố nhưng đó không phải là vấn đề. chúng ta chỉ cần một hàm cần nhiều tính toán

Bạn đã sử dụng các chức năng biên dịch C

Thay vì các vòng lặp và cờ while, chúng ta có thể sử dụng hàm có sẵn range(). Điều này vượt qua quá trình tạo, lặp lại và kiểm tra xem chúng tôi đã hoàn thành mô-đun C nhanh hơn nhiều chưa. Hãy nâng cấp chức năng khó chịu đó với range()

Lưu ý rằng mã này không chỉ dễ đọc hơn. nó cũng nhanh hơn. Chúng ta có thể sử dụng hai hàm này để tra cứu số lượng các số nguyên tố từ 0 đến 100. 000

[Vanilla] examined 100000 numbers; found 9592 primes in 30.38632 sec
[V+range] examined 100000 numbers; found 9592 primes in 20.00026 sec

Việc sử dụng một số mô-đun C tích hợp đã cải thiện một chút tốc độ thực thi nhưng chúng tôi mới chỉ bắt đầu

Chúng ta sẽ phải làm bẩn tay một chút nhưng kết quả sẽ rất phi thường (hình ảnh của Adi Goldstein trên Bapt) Viết mô-đun C cho Python

Việc đầu tiên chúng ta phải làm là chuyển hàm tìm nguyên tố sang C. Sau đó, bằng cách nào đó, chúng ta phải khiến Python nói chuyện với hàm C đó. Giải pháp cho việc này là bọc hàm C trong mô-đun Python

Bạn đã quen thuộc với những điều này; . g. Chúng tôi sẽ gọi mô-đun của chúng tôi là Fastcount

Ở cuối phần này, chúng ta sẽ cài đặt mô-đun để bạn có thể nhập mô-đun và thực thi một phương thức trên mô-đun như thế này

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25

Chúng tôi sẽ làm điều này trong 3 bước

  1. Viết lại hàm tìm số nguyên tố trong C
  2. Đóng gói hàm C trong mô-đun Python
  3. Xây dựng và cài đặt mô-đun

Bước 1. chức năng C

Phần này có thể hơi khó nếu bạn chưa quen với ngôn ngữ C. Nó giống như Python nhưng bị hạn chế hơn nhiều. Kiểm tra nó ra

Ngoài một số cú pháp ở đây và ở đó, hàm này trông rất giống với cú pháp khó chịu mà chúng ta đã viết trong chương trước

2. Gói chức năng C trong một mô-đun

Được rồi, vậy là chúng ta có một hàm được viết bằng C và một tệp Python. Làm cách nào chúng ta có thể truy cập hàm C từ tệp Python?

Làm thế nào tất cả các yếu tố phù hợp với nhau (hình ảnh của tác giả)

Chúng ta đã xác định hàm C của mình ở trên, vì vậy hãy bọc hàm C đó trong một đối tượng Python và (màu đen) và thực hiện theo cách của chúng ta

2. 1 bọc C-function thành một

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
0
Hãy đi qua mã

Hãy nhớ rằng mọi thứ trong Python đều là đối tượng? . Ngay cả việc khai báo kết quả số nguyên trong một

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
1. Về cơ bản, công cụ Python hoạt động với cấu trúc này để cho phép nhập động

Trong đoạn mã trên, chúng tôi đang gói hàm C của mình trong một

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
1. Hàm này phân tích cú pháp các đối số mà Python gửi cho chúng ta bằng cách sử dụng hàm
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
4.
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
5 chỉ ra rằng chúng tôi mong đợi hai số nguyên (thêm thông tin tại đây)

Tiếp theo, chúng ta gọi hàm C là số nguyên tố tìm được. Cuối cùng, chúng tôi trả về số lượng các số nguyên tố đã tìm được sau khi chúng tôi chuyển đổi chúng thành

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
6;

2. 2 thêm

import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
0 vào một
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
9
Đoạn mã dưới đây chỉ định tên hàm mà chúng ta gọi trong Python

Ở đây chúng tôi xác định danh sách tất cả các phương thức mà mô-đun của chúng tôi có

Trong ví dụ này, chúng tôi định nghĩa

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
0 là tên hàm; . Sau đó, chúng tôi đề cập đến chức năng tạo
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
1 từ bước trước.
Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
2 xác định chữ ký. nó mong đợi
Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
3 và
Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
4 từ Python. Cuối cùng, chúng tôi xác định mô tả phương thức cho chuỗi tài liệu

Chúng tôi có thể thêm nhiều đối tượng hơn vào đó nếu chúng tôi muốn mô-đun của mình có nhiều chức năng hơn nhưng với mục đích của bản demo này, chúng tôi sẽ giữ cho nó đơn giản.

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
5 này cũng yêu cầu dòng 3;

2. 3 Tạo

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
7 trên đó chúng tôi đăng ký tên mô-đun, mô tả và
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
9
Đây là mã

Đoạn mã này xác định mô-đun của chúng tôi. Mục đầu tiên là bắt buộc để tạo một

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
9. Trong dòng 4 và 5, chúng tôi chỉ định tên và mô tả của mô-đun của chúng tôi

Trong dòng 6, chúng ta có thể chỉ định dung lượng bộ nhớ cần thiết để lưu trữ trạng thái của chương trình. Nó được yêu cầu khi chương trình của bạn được sử dụng trong nhiều trình thông dịch phụ

Giá trị âm cho biết rằng mô-đun này không hỗ trợ trình thông dịch phụ. Chỉ định yêu cầu bộ nhớ của mô-đun của bạn sẽ được phân bổ trên mỗi phiên phiên dịch phụ với giá trị không âm

Mục cuối cùng, trong dòng 7, đề cập đến danh sách các phương thức mà chúng tôi đã chỉ định trong bước trước

2. 4 Tạo một range()0 để tạo mô-đun của chúng ta từ

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
7
mảnh ghép cuối cùng. Đây là hàm mà Python sẽ gọi khi nó nhập mô-đun của chúng ta lần đầu tiên

Chúng tôi sử dụng range()2 và chuyển cho nó một tham chiếu đến

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools
9 từ phần trước. Điều này sẽ trả về một
import Fastcount
res = Fastcount.primecounter(0, 100)
print(res)
# 25
1 trong đó hàm C của chúng ta được bao bọc. Kiểm tra toàn bộ mã ở đây

3. Xây dựng, cài đặt và chạy tiện ích mở rộng

Phần này tương tự như bước trong quá trình tạo Gói Python công khai hoặc riêng tư của riêng bạn. Chúng tôi phải tạo một tệp range()5 trỏ đến mã C của chúng tôi từ bước trước và sau đó tạo gói. Đi nào

Đoạn mã trên khá dễ hiểu;

Bước tiếp theo. chỉ cần gọi range()6. Điều này sẽ lấy tất cả mã của chúng tôi và đóng gói nó trong một mô-đun có tên là Fastcount. Bây giờ trong Python, chúng ta có thể

Xử lý sự cố

các cửa sổ. gọi điện cho range()6 có thể khiến bạn gặp lỗi khi đọc nội dung nào đó như

Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools

Bạn có thể giải quyết vấn đề này bằng cách cài đặt các công cụ xây dựng C++ mà bạn có thể tải xuống tại đây

Hãy chạy đua thuật toán (hình ảnh của Jonathan Chng trên Bapt)Đo điểm chuẩn

Hãy thử nghiệm mã của chúng ta; . 000. Để làm được điều này chúng ta cần kiểm tra khoảng 1. 3 tỷ số; . Chúng tôi đang đi đến điểm chuẩn

  • vani Python
  • vanilla Python + tích hợp sẵn (như phạm vi)
  • Fastcount (mô-đun C của chúng tôi)
  • MP đếm nhanh

Sau khi thực hiện tất cả các phương pháp nhiều lần và mất ít thời gian nhất, kết quả sẽ ở dạng. Tất cả các phương pháp tìm thấy số nguyên tố chính xác (41. 538) và đây là khoảng thời gian họ sử dụng (càng thấp càng tốt)

Thời gian thực hiện của tất cả các phương pháp tìm số nguyên tố trong một khoảng (càng thấp càng tốt, ảnh của tác giả)

Sử dụng các chức năng tích hợp sẵn như range() đã loại bỏ khoảng 35% thời gian cần thiết để hoàn thành. Mặc dù đây là một mức tăng khá tốt, mô-đun riêng của chúng tôi đã hoàn thành nhiệm vụ gần như range()9 so với vanilla Python

Để đạt được tốc độ cao hơn nữa, chúng tôi phân bổ tất cả các phép tính trên nhiều CPU bằng cách đa xử lý hàm của chúng tôi để hoàn thành phép tính của chúng tôi range()0 so với vanilla Python. Hãy xem bài viết này hoặc bài viết này để tìm hiểu thêm về đa tác vụ an toàn trong Python bằng cách sử dụng luồng và quy trình

Phần kết luận

Đây là một bài viết rất dài và khá phức tạp nhưng chúng ta đã học được rất nhiều về cách thức hoạt động của Python. Chúng tôi đã viết, biên dịch, đóng gói và nhập mô-đun C tùy chỉnh của riêng mình. Mặc dù bài viết này khá dài nhưng cuối cùng, chúng tôi đã giảm tốc độ thực thi từ hơn 10 phút xuống còn gần 6 giây. loại bỏ 99% thời gian thực hiện

Nếu bạn có góp ý/làm rõ xin vui lòng bình luận để tôi có thể cải thiện bài viết này. Trong thời gian chờ đợi, hãy xem các bài viết khác của tôi về tất cả các loại chủ đề liên quan đến lập trình như thế này

Python làm việc với C như thế nào?

Mã Python có thể gọi trực tiếp vào các mô-đun C . Các mô-đun C đó có thể là thư viện C chung hoặc thư viện được xây dựng riêng để hoạt động với Python. Cython tạo ra loại mô-đun thứ hai. Các thư viện C nói chuyện với nội bộ của Python và có thể được gói cùng với mã Python hiện có.

Chúng ta có thể tích hợp Python với C++ không?

Cũng có thể nhúng Python vào chương trình C++ ; . Không cần phải tự biên dịch lại Python bằng C++.