執行緒池的原理和連線池的原理

2021-07-09 17:51:33 字數 3620 閱讀 9876

一、 執行緒池的原理:

執行緒池,究竟是怎麼一回事?其實執行緒池的原理很簡單,類似於作業系統中的緩衝區的概念,它的流程如下:

先啟動若干數量的執行緒,並讓這些執行緒都處於睡眠狀態,當客戶端有乙個新請求時,就會喚醒執行緒池中的某乙個睡眠執行緒,讓它來處理客戶端的這個請求,當處理完這個請求後,執行緒又處於睡眠狀態。

可能你也許會問:為什麼要搞得這麼麻煩,如果每當客戶端有新的請求時,我就建立乙個新的執行緒不就完了?這也許是個不錯的方法,因為它能使得你編寫**相對容易一些,但你卻忽略了乙個重要的問題——效能

就拿我所在的單位來說,我的單位是乙個省級資料大集中的銀行網路中心,高峰期每秒的客戶端請求併發數超過100,如果為每個客戶端請求建立乙個新執行緒的話,那耗費的cpu時間和記憶體將是驚人的,如果採用乙個擁有200個執行緒的執行緒池,那將會節約大量的的系統資源,使得更多的cpu時間和記憶體用來處理實際的商業應用,而不是頻繁的執行緒建立與銷毀。

二、 資料庫連線池

資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現得尤為突出。

乙個資料庫連線物件均對應乙個物理資料庫連線,每次操作都開啟乙個物理連線,使用完都關閉連線,這樣造成系統的效能低下。 資料庫連線池的解決方案是在應用程式啟動時建立足夠的資料庫連線,並將這些連線組成乙個連線池(簡單說:在乙個「池」裡放了好多半成品的資料庫聯接物件),由應用程式動態地對池中的連線進行申請、使用和釋放。對於多於連線池中連線數的併發請求,應該在請求佇列中排隊等待。並且應用程式可以根據池中連線的使用率,動態增加或減少池中的連線數。

連線池技術盡可能多地重用了消耗記憶體地資源,大大節省了記憶體,提高了伺服器地服務效率,能夠支援更多的客戶服務。通過使用連線池,將大大提高程式執行效率,同時,我們可以通過其自身的管理機制來監視資料庫連線的數量、使用情況等。

1) 最小連線數是連線池一直保持的資料庫連線,所以如果應用程式對資料庫連線的使用量不大,將會有大量的資料庫連線資源被浪費;

2) 最大連線數是連線池能申請的最大連線數,如果資料庫連線請求超過此數,後面的資料庫連線請求將被加入到等待佇列中,這會影響之後的資料庫操作。

三、 linux執行緒池的c語言實現

通常我們使用多執行緒的方式是,需要時建立乙個新的執行緒,在這個新的執行緒裡執行特定的任務,然後在任務完成後退出。這在一般的應用裡已經能夠滿足我們應用的需要,畢竟我們並不是什麼時候都需要建立大量的執行緒,並在它們執行乙個簡單的任務後銷毀。

但是在一些web、email、database等應用裡,比如彩鈴,我們的應用在任何時候都要準備應對數目巨大的連線請求,同時,這些請求所要完成的任務卻又可能非常的簡單,即只占用很少的處理時間。這時,我們的應用有可能處於不停的建立執行緒並銷毀執行緒的狀態。雖說比起程序的建立,執行緒的建立時間已經大大縮短,但是如果需要頻繁的建立執行緒,並且每個執行緒所占用的處理時間又非常簡短,則執行緒建立和銷毀帶給處理器的額外負擔也是很可觀的。

執行緒池的作用正是在這種情況下有效的降低頻繁建立銷毀執行緒所帶來的額外開銷。一般來說,執行緒池都是採用預建立的技術,在應用啟動之初便預先建立一定數目的執行緒。應用在執行的過程中,需要時可以從這些執行緒所組成的執行緒池裡申請分配乙個空閒的執行緒,來執行一定的任務,任務完成後,並不是將執行緒銷毀,而是將它返還給執行緒池,由執行緒池自行管理。如果執行緒池中預先分配的執行緒已經全部分配完畢,但此時又有新的任務請求,則執行緒池會動態的建立新的執行緒去適應這個請求。當然,有可能,某些時段應用並不需要執行很多的任務,導致了執行緒池中的執行緒大多處於空閒的狀態,為了節省系統資源,執行緒池就需要動態的銷毀其中的一部分空閒執行緒。因此,執行緒池都需要乙個管理者,按照一定的要求去動態的維護其中執行緒的數目。

為了使這個執行緒池庫使用起來更加方便,我在c實現中加入了一些oo的思想,與objective-c不同,它僅僅是使用struct模擬了c++中的類,在linux的源**和一些應用,比如xine裡,我們可以看到這種使用方式。

在這個庫里,與使用者有關的介面主要有:

typedef struct tp_work_desc_s tp_work_desc;

typedef struct tp_work_s tp_work;

typedef struct tp_thread_info_s tp_thread_info;

typedef struct tp_thread_pool_s tp_thread_pool;

//thread parm
struct tp_work_desc_s;

//base thread struct

struct tp_work_s;

tp_thread_pool *creat_thread_pool(int min_num, int max_num);

tp_work_desc_s表示應用執行緒執行任務時所需要的一些資訊,會被當作執行緒的引數傳遞給每個執行緒,依據應用的不同而不同,需要使用者定義結構的內容。tp_work_s就是我們希望執行緒執行的任務了。當我們申請分配乙個新的執行緒時,首先要明確的指定這兩個結構,即該執行緒完成什麼任務,並且完成這個任務需要哪些額外的資訊。介面函式creat_thread_pool用來建立乙個執行緒池的例項,使用時需要指定該執行緒池例項所能容納的最小執行緒數min_num和最大執行緒數max_num。最小執行緒數即執行緒池建立時預建立的執行緒數目,這個數目的大小也直接影響了執行緒池所能起到的效果,如果指定的太小,執行緒池中預建立的執行緒很快就將分配完畢並需要建立新的執行緒來適應不斷的請求,如果指定的太大,則將可能會有大量的空閒執行緒。我們需要根據自己應用的實際需要進行指定。描述執行緒池的結構如下:

//main thread pool struct

struct tp_thread_pool_s{

tpbool (*init)(tp_thread_pool *this);

void (*close)(tp_thread_pool *this);

void (*process_job)(tp_thread_pool *this, tp_work *worker, tp_work_desc *job);

int (*get_thread_by_id)(tp_thread_pool *this, int id);

tpbool (*add_thread)(tp_thread_pool *this);

tpbool (*delete_thread)(tp_thread_pool *this);

int (*get_tp_status)(tp_thread_pool *this);

int min_th_num;                //min thread number in the pool

int cur_th_num; //current thread number in the pool

int max_th_num; //max thread number in the pool

pthread_mutex_t tp_lock;

pthread_t manage_thread_id; //manage thread id num

tp_thread_info *thread_info; //work thread relative thread info

在已經建立並初始化了執行緒池之後,我們就可以指定tp_work_desc_s和tp_work_s結構,並使用執行緒池的process_job介面來執行它們。這些就是我們使用這個執行緒池時所需要了解的所有東西。如果不再需要執行緒池,可以使用close介面銷毀它。

執行緒池的原理和連線池的原理

執行緒池的原理 來看一下執行緒池究竟是怎麼一回事?其實執行緒池的原理很簡單,類似於作業系統中的緩衝區的概念,它的流程如下 先啟動若干數量的執行緒,並讓這些執行緒都處於睡眠狀態,當客戶端有乙個新請求時,就會喚醒執行緒池中的某乙個睡眠執行緒,讓它來處理客戶端的這個請求,當處理完這個請求後,執行緒又處於睡...

執行緒池的原理和連線池的原理

一 執行緒池的原理 執行緒池,究竟是怎麼一回事?其實執行緒池的原理很簡單,類似於作業系統中的緩衝區的概念,它的流程如下 先啟動若干數量的執行緒,並讓這些執行緒都處於睡眠狀態,當客戶端有乙個新請求時,就會喚醒執行緒池中的某乙個睡眠執行緒,讓它來處理客戶端的這個請求,當處理完這個請求後,執行緒又處於睡眠...

執行緒池的原理和連線池的原理

來自 執行緒池的原理 來看一下執行緒池究竟是怎麼一回事?其實執行緒池的原理很簡單,類似於作業系統中的緩衝區的概念,它的流程如下 先啟動若干數量的執行緒,並讓這些執行緒都處於睡眠狀態,當客戶端有乙個新請求時,就會喚醒執行緒池中的某乙個睡眠執行緒,讓它來處理客戶端的這個請求,當處理完這個請求後,執行緒又...