C / C ++ dari Python (boost)

utama

Artikel terakhir dalam seri tentang cara menjalankan C / C ++ dari Python3 membahas semua cara yang diketahui untuk melakukan ini. Kali ini saya harus meningkatkan . Apa yang terjadi dari ini baca di bawah.


C


Saya mengambil contoh yang sama dari perpustakaan tes sebagai dasar dan menjadikannya variasi untuk metode tertentu. Pustaka uji untuk mendemonstrasikan bekerja dengan variabel global, struktur, dan fungsi dengan argumen dari berbagai jenis.


test.c:


#include "test.hpp" int a = 5; double b = 5.12345; char c = 'X'; int func_ret_int(int val) { printf("C get func_ret_int: %d\n", val); return val; } double func_ret_double(double val) { printf("C get func_ret_double: %f\n", val); return val; } object func_ret_str(char *val) { printf("C get func_ret_str: %s\n", val); return object(string(val)); } char func_many_args(int val1, double val2, char val3, short val4) { printf("C get func_many_args: int - %d, double - %f, char - %c, short - %d\n", val1, val2, val3, val4); return val3; } test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { printf("C get test_st: val1 - %d, val2 - %f, val3 - %c\n", test_st->val1, test_st->val2, test_st->val3); } return test_st; } // _test    BOOST_PYTHON_MODULE(_test) { /* *   */ def("func_ret_int", func_ret_int); def("func_ret_double", func_ret_double); def("func_ret_str", &func_ret_str); def("func_many_args", func_many_args); //   // manage_new_object C     // reference_existing_object C     def("func_ret_struct", &func_ret_struct, return_value_policy<reference_existing_object>()); /* *    */ scope().attr("a") = a; scope().attr("b") = b; scope().attr("c") = c; /* *  */ class_<test_st_t>("test_st_t") .def_readwrite("val1", &test_st_t::val1) .def_readwrite("val2", &test_st_t::val2) .def_readwrite("val3", &test_st_t::val3) ; } 

test.h:


 using namespace boost::python; using namespace std; #ifdef __cplusplus extern "C" { #endif typedef struct test_st_s test_st_t; typedef char * char_p; extern int a; extern double b; extern char c; int func_ret_int(int val); double func_ret_double(double val); object func_ret_str(char *val); char func_many_args(int val1, double val2, char val3, short val4); test_st_t *func_ret_struct(test_st_t *test_st); struct test_st_s { int val1; double val2; char val3; }; #ifdef __cplusplus } #endif 

Cara mengompilasi:


 g++ -g -fPIC -I/usr/include/python3.6 -I./src/c -o ./objs/test.o -c ./src/c/test.cpp g++ -fPIC -g -shared -o ./lib/_test.so ./objs/test.o -lboost_python3 

Sumber mengkompilasi ke perpustakaan dinamis.
python boost mirip dengan yang digunakan pada pybind11 , Anda juga perlu menjelaskan fungsi-fungsi yang akan dilihat python. Tapi menurut saya, meningkatkan lebih besar dan rumit. Sebagai contoh:


 def("func_ret_struct", &func_ret_struct, return_value_policy<reference_existing_object>()); 

Fungsi func_ret_struct mengambil sebagai argumen penunjuk ke struktur dan mengembalikan penunjuk yang sama kembali. Untuk itu, Anda perlu menentukan aturan objek yang dikembalikan return_value_policy <reference_existing_object> () . reference_existing_objec mengatakan bahwa objek yang dikembalikan sudah ada. Jika Anda menentukan manage_new_object, itu berarti kami mengembalikan objek baru. Dalam hal ini, skrip tersebut akan jatuh ke dalam segmentasi kesalahan pada pengumpul sampah:


 test_st = _test.test_st_t() ret = _test.func_ret_struct(test_st) 

Karena pengumpul sampah pertama-tama akan menghapus data yang berisi test_st, dan kemudian ingin menghapus data yang berisi objek ret. Yang berisi data yang sama dengan test_st yang terkandung, tetapi sudah dihapus.


Sangat menarik bagaimana dalam hal ini untuk menggambarkan fungsi seperti itu (tidak masuk terlalu dalam)?:


 test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { return test_st; } else { return (test_st_t *) malloc(sizeof(test_st_t)); } } 

Fungsi seperti itu dapat mengembalikan objek yang ada maupun yang sudah ada.


Saya juga punya masalah dengan fungsi seperti itu:


 char * func_ret_str(char *val) { return val; } 

Seperti yang saya pahami, Anda tidak bisa mendapatkan pointer ke tipe data standar dari python di boost. Itu hanya mungkin pada struct , kelas dan gabungan . Jika ada yang tahu cara untuk mencerahkan.


Python


Untuk python, modul menjadi asli.
main.py:


 #!/usr/bin/python3 #-*- coding: utf-8 -*- import sys import time #    test #sys.path.append('.') sys.path.append('lib/') #   import _test ### ## C ### print("boost\n") print("C\n") start_time = time.time() ## #    ## print('  :') print('ret func_ret_int: ', _test.func_ret_int(101)) print('ret func_ret_double: ', _test.func_ret_double(12.123456789)) print('ret func_ret_str: ', _test.func_ret_str('Hello!')) print('ret func_many_args: ', _test.func_many_args(15, 18.1617, 'X', 32000)) ## #    ## print('\n  :') print('ret a: ', _test.a) #   . _test.a = 22 print('new a: ', _test.a) print('ret b: ', _test.b) print('ret c: ', _test.c) ## #    ## print('\n  :') #      test_st = _test.test_st_t() test_st.val1 = 5 test_st.val2 = 5.1234567 test_st.val3 = 'Z' print('val1 = {}\nval2 = {}\nval3 = {}'.format(test_st.val1, test_st.val2, test_st.val3)) ret = _test.func_ret_struct(test_st) #    C print('ret val1 = {}\nret val2 = {}\nret val3 = {}'.format(ret.val1, ret.val2, ret.val3)) #   print("--- {} seconds ---".format(time.time() - start_time)) 

Pro dan kontra dorongan


Pro :


  • sintaksis sederhana ketika digunakan dalam Python

Cons :


  • Anda perlu mengedit sumber C ++, atau menulis ikatan untuknya
  • meningkatkan saja tidak mudah

Kodenya, seperti biasa, saya coba komentari dengan jelas.


Waktu pelaksanaan pengujian rata-rata pada setiap metode dengan 1000 dimulai:


  • ctypes: - 0,0004987692832946777 detik ---
  • CFFI: - 0,00038521790504455566 detik ---
  • pybind: - 0,0004547207355499268 detik ---
  • API C: - 0,00035619735717773444 detik ---
  • boost: - 0,00037789344787597656 detik ---

Referensi


Source: https://habr.com/ru/post/id471618/


All Articles