一個mysql客戶端項目中,所有的參數都保存到mysql中,需要頻繁的訪問mysql server,其實使用一個mysql長連接也可以滿足要求,但為了更好的利用多核CPU嘗試使用連接池來充分發揮多線程的優勢(電腦配置 i7-4核8線程)。
下面是mysql_pool實現的源碼,
1. 頭文件 mysql_pool.h
1 // 2 // 創建人: levy 3 // 創建時間:Jun 5, 2017 4 // 功能:mysql_pool.h 5 // Copyright (c) 2017 levy. All Rights Reserved. 6 // Ver 變更日期 負責人 變更內容 7 // ────────────────────────────────────────────────────────────────────────── 8 // V0.01 Jun 5, 2017 levy 初版 9 // 10 11 12 #ifndef MYSQL_POOL_H_ 13 #define MYSQL_POOL_H_ 14 #include <mysql.h> 15 #include <pthread.h> 16 #define MAX_KEPP_CONNECTIONS 8 17 typedef struct mysql_conn //mysql連接鏈表結構體定義 18 { 19 struct mysql_conn * next; 20 struct mysql_conn * prev; 21 MYSQL conn; 22 23 }mysql_conn; 24 25 typedef struct mysql_pool //mysql連接池結構體定義 26 { 27 char host[64]; //主機名稱 28 char username[32]; //用戶名 29 char passwd[32]; //密碼 30 char database[32]; //默認數據庫 31 int s_port; //端口號,默認3306 32 int max_connections; //保持開啟的mysql最大連接數 33 int free_connections; //當前空閑的mysql連接數 34 int is_idle_block; //是否開啟了無可用連接阻塞 35 pthread_mutex_t lock; //mysql鏈表鎖 36 pthread_cond_t idle_signal; //等待可用連接的條件變量 37 mysql_conn * mysql_list; //mysql連接池鏈表 38 }mysql_pool; 39 40 void mysql_pool_init(); 41 void destory_mysql_pool(); 42 void destory_mysql_connection(mysql_conn *conn); 43 void release_mysql_connection(mysql_conn *conn); 44 mysql_conn * get_mysql_connection(); 45 46 MYSQL_RES* mysql_execute_query(const char *sql,unsigned long length,int *flag); 47 48 #endif /* MYSQL_POOL_H_ */
2.連接池實現 1 //
2 // 創建人: levy 3 // 創建時間:Jun 5, 2017 4 // 功能:mysql_pool.c 5 // Copyright (c) 2016 levy. All Rights Reserved. 6 // Ver 變更日期 負責人 變更內容 7 // ────────────────────────────────────────────────────────────────────────── 8 // V0.01 Jun 5, 2017 levy 初版 9 // 10 11 #include "mysql_pool.h" 12 #include <stdlib.h> 13 #include <string.h> 14 #include <errno.h> 15 #include <stdio.h> 16 static mysql_pool pool_mysql;//連接池定義 17 unsigned int query_times = 0;//mysql所有的查詢次數,用於測試 18 19 /*創建一個新的mysql連接 20 * @return NULL代表創建失敗。 21 */ 22 mysql_conn * mysql_new_connection() 23 { 24 mysql_conn * conn=malloc(sizeof(mysql_conn)); 25 if(mysql_init(&conn->conn)==NULL) 26 { 27 printf("can not init mysql: [%s]\n",strerror(errno)); 28 free(conn); 29 return NULL; 30 } 31 if(mysql_options(&conn->conn, MYSQL_SET_CHARSET_NAME, "UTF8")!=0) 32 { 33 printf("can not set mysql options[errno = %d]: [%s]\n",mysql_errno(&conn->conn),mysql_error(&conn->conn)); 34 free(conn); 35 return NULL; 36 } 37 //連接到mysql服務端,設置CLIENT_MULTI_STATEMENTS通知服務器客戶端可以處理由多語句或者存儲過程執行生成的多結果集 38 if(mysql_real_connect(&conn->conn,pool_mysql.host,pool_mysql.username,pool_mysql.passwd,pool_mysql.database,pool_mysql.s_port,NULL, CLIENT_MULTI_STATEMENTS)==NULL) 39 { 40 printf("can not connect mysql server[errno = %d]: [%s]\n",mysql_errno(&conn->conn),mysql_error(&conn->conn)); 41 free(conn); 42 return NULL; 43 } 44 conn->next = NULL; 45 conn->prev = NULL; 46 return conn; 47 } 48 49 /*向鏈接池中壓入一個mysql連接conn 50 * */ 51 void conn_push(mysql_conn * conn) 52 { 53 mysql_conn *lc = pool_mysql.mysql_list; 54 if(lc==NULL) 55 { 56 pool_mysql.mysql_list=conn; 57 58 }else 59 { 60 while(lc->next) 61 { 62 lc=lc->next; 63 } 64 lc->next = conn; 65 conn->prev = lc; 66 67 } 68 pool_mysql.free_connections++; 69 } 70 71 /*從連接池中出棧一個mysql連接 72 * @return NULL表示連接池中沒有可用的連接 73 * */ 74 mysql_conn * conn_pop() 75 { 76 mysql_conn*conn = pool_mysql.mysql_list; 77 if(conn != NULL) 78 { 79 80 pool_mysql.mysql_list = conn->next; 81 if(pool_mysql.mysql_list) 82 { 83 pool_mysql.mysql_list->prev = NULL; 84 } 85 pool_mysql.free_connections--; 86 } 87 return conn; 88 } 89 90 /*初始化mysql連接池*/ 91 void mysql_pool_init() 92 { 93 mysql_conn * conn; 94 strncpy(pool_mysql.host,"localhost",sizeof(pool_mysql.host)); 95 strncpy(pool_mysql.username,"test",sizeof(pool_mysql.username)); 96 strncpy(pool_mysql.passwd,"test",sizeof(pool_mysql.passwd)); 97 strncpy(pool_mysql.database,"test",sizeof(pool_mysql.database)); 98 pool_mysql.s_port = 3306; 99 pool_mysql.max_connections=MAX_KEEP_CONNECTIONS; 100 pool_mysql.free_connections = 0; 101 pool_mysql.mysql_list = NULL; 102 pool_mysql.is_idle_block = 0; 103 pthread_mutex_init(&pool_mysql.lock,NULL); 104 pthread_cond_init(&pool_mysql.idle_signal,NULL); 105 pthread_mutex_lock(&pool_mysql.lock); 106 for(int i=0;i<pool_mysql.max_connections;i++) 107 { 108 conn=mysql_new_connection(); 109 if(conn) 110 { 111 conn_push(conn); 112 }else 113 { 114 115 } 116 117 } 118 pthread_mutex_unlock(&pool_mysql.lock); 119 } 120 121 /*從連接池中獲取一個mysql連接*/ 122 mysql_conn * get_mysql_connection() 123 { 124 pthread_mutex_lock(&pool_mysql.lock); 125 mysql_conn *conn = conn_pop(); 126 pthread_mutex_unlock(&pool_mysql.lock); 127 return conn; 128 } 129 130 /*從連接池中獲取一個mysql連接,如果連接池為空,測阻塞*/ 131 mysql_conn * get_mysql_connection_block() 132 { 133 pthread_mutex_lock(&pool_mysql.lock); 134 mysql_conn *conn = conn_pop(); 135 while(conn == NULL) 136 { 137 pool_mysql.is_idle_block ++; 138 pthread_cond_wait(&pool_mysql.idle_signal,&pool_mysql.lock); 139 conn = conn_pop(); 140 pool_mysql.is_idle_block --; 141 } 142 query_times++; 143 pthread_mutex_unlock(&pool_mysql.lock); 144 return conn; 145 } 146 147 148 /*回收一個mysql連接到連接池*/ 149 void release_mysql_connection(mysql_conn *conn) 150 { 151 pthread_mutex_lock(&pool_mysql.lock); 152 conn->next = NULL; 153 conn->prev = NULL; 154 conn_push(conn); 155 if(pool_mysql.is_idle_block) 156 { 157 pthread_cond_signal(&pool_mysql.idle_signal); 158 } 159 pthread_mutex_unlock(&pool_mysql.lock); 160 } 161 162 /*銷毀一個mysql連接,並釋放其占用的資源*/ 163 void destory_mysql_connection(mysql_conn *conn) 164 { 165 mysql_close(&conn->conn); 166 free(conn); 167 } 168 169 //銷毀連接池中的所有連接 170 void destory_mysql_pool() 171 { 172 mysql_conn *conn; 173 pthread_mutex_lock(&pool_mysql.lock); 174 conn = conn_pop(); 175 for(;conn;conn = conn_pop()) 176 { 177 destory_mysql_connection(conn); 178 } 179 pthread_mutex_unlock(&pool_mysql.lock); 180 } 181 182 183 MYSQL_RES* mysql_execute_query(const char *sql,unsigned long length,int *flag) 184 { 185 int res; 186 MYSQL_RES *res_ptr; 187 mysql_conn*con = get_mysql_connection_block(); 188 if(con == NULL) 189 { 190 printf("can not get mysql connections from the pools\n"); 191 *flag =-2; 192 return NULL; 193 } 194 *flag=0; 195 res=mysql_real_query(&con->conn,sql,length); 196 if(res!=0) 197 { 198 printf("mysql_real_query error [errno = %d]: [%s]\n",mysql_errno(&con->conn),mysql_error(&con->conn)); 199 release_mysql_connection(con); 200 *flag=res; 201 return NULL; 202 } 203 res_ptr = mysql_store_result(&con->conn); 204 if(res_ptr == NULL) 205 { 206 printf("mysql_store_result error [errno = %d]: [%s]\n",mysql_errno(&con->conn),mysql_error(&con->conn)); 207 } 208 release_mysql_connection(con); 209 return res_ptr; 210 } 2113.測試主函數main.c,同時創建10000個線程 1 2 // 創建人: levy
3 // 創建時間:May 25, 2017 4 // 功能:main.c 5 // Copyright (c) 2016 levy. All Rights Reserved. 6 // Ver 變更日期 負責人 變更內容 7 // ────────────────────────────────────────────────────────────────────────── 8 // V0.01 May 25, 2017 levy 初版 9 // 10 11 #include <stdlib.h> 12 #include <stdio.h> 13 #include <unistd.h> 14 #include <time.h> 15 #include <sys/time.h> 16 #include <pthread.h> 17 #include <string.h> 18 #include <errno.h> 19 #include "mysql_pool.h" 20 21 const char *test_sql = "SELECT ID,Name,Value,RecordTime FROM test where ID <1024"; 22 extern unsigned int query_times ; 23 24 25 void * test_thread(void *arp) 26 { 27 int flag=0; 28 int count=0; 29 MYSQL_RES * resptr; 30 //for(int i=0;i<10;i++) 31 { 32 resptr=mysql_execute_query(test_sql,strlen(test_sql),&flag); 33 if(resptr) 34 { 35 count++; 36 mysql_free_result(resptr); 37 }else 38 { 39 perror("error"); 40 } 41 } 42 //printf("I has finsh %d query.\n",count); 43 pthread_exit(NULL); 44 } 45 46 47 48 #define thread_nums 10000 49 int main(void ) 50 { 51 mysql_pool_init(); 52 pthread_t th[thread_nums]; 53 struct timeval tnow,tnow1,tnow2; 54 gettimeofday(&tnow1, NULL); 55 printf("start time tv_sec = %ld,tv_usec = %ld \n",tnow1.tv_sec,tnow1.tv_usec); 56 for(int i=0;i<thread_nums;i++) 57 { 58 pthread_create(&th[i],NULL,test_thread,NULL); 59 } 60 for(int i=0;i<thread_nums;i++) 61 { 62 pthread_join(th[i],NULL); 63 } 64 gettimeofday(&tnow2, NULL); 65 timersub(&tnow2,&tnow1,&tnow); 66 printf("Max keep connections = %d,max_thread_nums=%d,total query times=%d,use %ld ms",MAX_KEPP_CONNECTIONS,thread_nums,query_times,tnow.tv_sec*1000+tnow.tv_usec/1000);
67 //printf("total time tv_sec = %ld.%3ld s \n",); 68 destory_mysql_pool(); 69 pthread_exit(NULL); 70 }
測試結果
1.Max keep connections = 1,max_thread_nums=10000,total query times=10000,use 6114 ms
2.Max keep connections = 2,max_thread_nums=10000,total query times=10000,use 3404 ms
3.Max keep connections = 4,max_thread_nums=10000,total query times=10000,use 1958 ms
4.Max keep connections = 8,max_thread_nums=10000,total query times=10000,use 1794 ms
5.Max keep connections = 16,max_thread_nums=10000,total query times=10000,use 1787 ms
總結:從測試結果可以看出保持最大連接數目為cpu的核心數能夠充分發揮cpu多核的優勢。
編輯日期:2017-06-05 16:55:39