前几篇的blog都是为了这个实验做基础,先说
原因是python调用数据库150w条数据22s,然后处理数据,其实就2个简单的for循环,65s
需求:
1. python调用c++函数
2. c++调用mysql,查询数据,逻辑处理(暂时不用,稍微复杂)直接打印就好,然后返回给python
3. python收到处理后的数据,打印
实验结果:
c++调用mysql报错mysql.h error到现在也没解决,只能改成c用
结果就是3s处理完了,简直完爆,牛的可怕
涉及知识:
debian系列下c++调用mysql, linux下面安装mysql.h文件
1. python调用简单c或c++代码样例
例子1:
例子1我没测试。
#include<iostream> using namespace std; void foo2(int a,int b) { cout<<a<<" "<<b<<endl; } //编译C++,一定要加extern "C",注意C为大写,小写会无法识别 extern "C" { void cfoo2(int a,int b) { foo2(a,b); } }
g++ -o test1.so -shared -fPIC test1.cpp
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件; -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
import ctypes ll = ctypes.cdll.LoadLibrary lib = ll("./test1.so") lib.cfoo2(3, 4)
例子2:
已测试
c++代码
extern "C" { int sum(){ return 20; } }
标准代码:
#ifdef __cplusplus extern "C" { int sum(){ return 20; } } #endif
为什么?
这样的代码到底是什么意思呢?首先,__cplusplus是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。 要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.
当然我的超级c++版本
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <mysql/mysql.h> #include <time.h> #include <iostream> #include <string> #include <set> using namespace std; MYSQL *g_conn; // mysql 连接 MYSQL_RES *g_res; // mysql 记录集 MYSQL_ROW g_row; // 字符串数组,mysql 记录行 #define MAX_BUF_SIZE 1024 // 缓冲区最大字节数 const char *g_host_name = "localhost"; const char *g_user_name = "root"; const char *g_password = "python123"; const char *g_db_name = "db_data_20170524164100"; const unsigned int g_db_port = 3306; void print_mysql_error(const char *msg) // 打印最后一次错误 { if (msg) printf("%s: %s\n", msg, mysql_error(g_conn)); else puts(mysql_error(g_conn)); } int executesql(const char * sql) { /*query the database according the sql*/ if (mysql_real_query(g_conn, sql, strlen(sql))) // 如果失败 return -1; // 表示失败 return 0; // 成功执行 } int init_mysql() // 初始化连接 { // init the database connection g_conn = mysql_init(NULL); /* connect the database */ if(!mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, NULL, 0)) // 如果失败 return -1; // 是否连接已经可用 executesql("set names utf8"); // 如果失败 // return -1; return 0; // 返回成功 } extern "C" { int mysqlPP() { if (init_mysql()); print_mysql_error(NULL); char sql[MAX_BUF_SIZE]; int firstTime = time((time_t*)NULL); printf("firstTime is: %d\n", firstTime); if (executesql("select * from data_stats_gov_cn_diqu_niandu")) // 句末没有分号 print_mysql_error(NULL); g_res = mysql_store_result(g_conn); // 从服务器传送结果集至本地,mysql_use_result直接使用服务器上的记录集 int iNum_rows = mysql_num_rows(g_res); // 得到记录的行数 int iNum_fields = mysql_num_fields(g_res); // 得到记录的列数 printf("共%d个记录,每个记录%d字段\n", iNum_rows, iNum_fields); set<string> myset; set<string>::iterator it; while ((g_row=mysql_fetch_row(g_res))) // 打印结果集 myset.insert(g_row[4]); // spacename int secodnTime = time((time_t*)NULL); printf("secodnTime is: %d\n", secodnTime); for (it=myset.begin(); it!=myset.end(); ++it)
编译c++的命令
g++ -g -o mysql.so -I /usr/include/mysql main.cpp -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -lz -lpthread -shared -fPIC
编译的时候要注意用到2个路径,mysql.h和libmysqlclient.so的路径
查找mysql.h路径
[root@liu mysql]# find / -name 'mysql.h' /usr/include/mysql/mysql.h
[root@liu mysql]# find / -name '*mysqlclient*' /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.0.0 /usr/lib/x86_64-linux-gnu/libmysqlclient_r.so.18 /usr/lib/x86_64-linux-gnu/libmysqlclient.a /usr/lib/x86_64-linux-gnu/libmysqlclient_r.a /usr/lib/x86_64-linux-gnu/libmysqlclient.so /usr/lib/x86_64-linux-gnu/libmysqlclient_r.so /usr/lib/x86_64-linux-gnu/libmysqlclient_r.so.18.0.0 /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18
python代码
#!/usr/bin/env python # -*- coding:utf-8 -*- import time from ctypes import * def main(): start_time = time.time() result = cdll.LoadLibrary("./test.so") print(result.sum(1, 2)) if __name__ == '__main__': main()