新聞中心
隨著互聯(lián)網(wǎng)技術(shù)的不斷發(fā)展,服務(wù)端編程技術(shù)也得到了很大的發(fā)展,成為了傳統(tǒng)軟件開發(fā)的重要領(lǐng)域。在服務(wù)端編程技術(shù)中,多線程編程技術(shù)是一個重要的組成部分。而其中的linux多線程服務(wù)端編程技術(shù),更是目前比較流行的一種編程方式。

成都創(chuàng)新互聯(lián)是專業(yè)的巴宜網(wǎng)站建設(shè)公司,巴宜接單;提供網(wǎng)站建設(shè)、成都網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行巴宜網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
本篇文章就將結(jié)合實(shí)際項(xiàng)目開發(fā),探討Linux多線程服務(wù)端編程的一些實(shí)踐技巧以及注意事項(xiàng)。
一、多線程服務(wù)端編程架構(gòu)
在構(gòu)建多線程服務(wù)端應(yīng)用時,需要考慮應(yīng)用的架構(gòu)。一般而言,多線程服務(wù)端應(yīng)用的架構(gòu)應(yīng)該包含以下幾個組件:
1. 并發(fā)請求接收器:可以使用select、epoll 或者libev等等工具庫來實(shí)現(xiàn)。其主要作用是接收并行的客戶請求。
2. 主邏輯處理器:在收到客戶請求后,主邏輯處理器將處理客戶請求并且返回響應(yīng)。這個部分更好采用多線程的方式來實(shí)現(xiàn),以達(dá)到更高的并發(fā)性能。
3. 數(shù)據(jù)庫連接池:多線程服務(wù)端應(yīng)用需要與數(shù)據(jù)庫或者其他外部資源交互。因此需要使用連接池來管理和優(yōu)化數(shù)據(jù)庫連接的使用。
4. 緩存機(jī)制:緩存是提高應(yīng)用性能和響應(yīng)速度的重要手段。多線程服務(wù)端應(yīng)用中,緩存機(jī)制可以存儲應(yīng)用中經(jīng)常使用的數(shù)據(jù),避免頻繁地使用外部資源??梢圆捎肕emcached、Redis等緩存服務(wù)器來實(shí)現(xiàn)。
二、多線程服務(wù)端編程的實(shí)際應(yīng)用
在實(shí)際開發(fā)時,應(yīng)該使用優(yōu)秀的多線程編程技術(shù)來提高服務(wù)端應(yīng)用的并發(fā)性。若格外關(guān)注這方面的編碼細(xì)節(jié),能夠?qū)崿F(xiàn)應(yīng)用很高的響應(yīng)速度以及更高的并發(fā)性能。下面將深入探討在實(shí)際開發(fā)背景下如何使用多線程編程技術(shù)。
1. 使用線程池
線程池可以有效地提高多線程服務(wù)端的性能。由于線程的創(chuàng)建和銷毀是相對較慢的操作,因此,可以預(yù)先分配一定數(shù)量的線程,把它們放在一個隊(duì)列中。當(dāng)需要多線程處理請求時,就從隊(duì)列中獲取一個空閑的線程來執(zhí)行所需要的操作,處理完后再放回隊(duì)列中。
代碼示例:
“`cpp
#include
#include
#include
#include
#define MAX_THREADS 16
#define MAX_QUEUE 65535
typedef struct task_struct {
void *(*func)(void *arg);
void *arg;
} task_t;
struct thread_pool {
pthread_mutex_t lock;
pthread_cond_t notify;
pthread_t *threads;
task_t *queue;
int thread_count;
int task_count;
int head;
int tl;
int shutdown;
int started;
};
typedef struct thread_pool thread_pool_t;
// 初始化線程池
void thread_pool_init(thread_pool_t *pool, int threads_count);
// 關(guān)閉線程池
void thread_pool_shutdown(thread_pool_t *pool);
// 向任務(wù)隊(duì)列放一個任務(wù)
int thread_pool_push(thread_pool_t *pool, void *(*func)(void *), void *arg);
static void *thread_routine(void *arg);
void thread_pool_init(thread_pool_t *pool, int threads_count) {
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->notify, NULL);
pool->threads = (pthread_t*)malloc(sizeof(pthread_t)*threads_count);
pool->queue = (task_t*)malloc(sizeof(task_t)*MAX_QUEUE);
pool->thread_count = threads_count;
pool->task_count = 0;
pool->shutdown = 0;
pool->started = 0;
pool->head = pool->tl = 0;
for (int i = 0; i
pthread_create(&pool->threads[i], NULL, thread_routine, (void*)pool);
}
}
// 添加一個任務(wù)到線程池
int thread_pool_push(thread_pool_t *pool, void *(*func)(void *), void *arg) {
pthread_mutex_lock(&pool->lock);
if (pool->task_count == MAX_QUEUE) {
pthread_mutex_unlock(&pool->lock);
return -1;
}
pool->queue[pool->tl].func = func;
pool->queue[pool->tl].arg = arg;
pool->tl = (pool->tl + 1) % MAX_QUEUE;
pool->task_count++;
pthread_cond_signal(&pool->notify);
pthread_mutex_unlock(&pool->lock);
return 0;
}
void thread_pool_shutdown(thread_pool_t *pool) {
pthread_mutex_lock(&pool->lock);
pool->shutdown = 1;
pthread_mutex_unlock(&pool->lock);
pthread_cond_broadcast(&pool->notify);
for (int i = 0; i thread_count; ++i) {
pthread_join(pool->threads[i], NULL);
}
free(pool->threads);
for (int i = 0; i task_count; ++i) {
free(pool->queue[i].arg);
}
free(pool->queue);
pthread_mutex_destroy(&pool->lock);
pthread_cond_destroy(&pool->notify);
}
static void *thread_routine(void *arg) {
thread_pool_t *pool = (thread_pool_t*) arg;
while (1) {
pthread_mutex_lock(&pool->lock);
while (pool->task_count == 0 && !pool->shutdown) {
pthread_cond_wt(&pool->notify, &pool->lock);
}
if (pool->shutdown) {
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
}
task_t task;
task.func = pool->queue[pool->head].func;
task.arg = pool->queue[pool->head].arg;
pool->head = (pool->head + 1) % MAX_QUEUE;
pool->task_count–;
pthread_mutex_unlock(&pool->lock);
(*(task.func))(task.arg);
}
pthread_exit(NULL);
}
“`
2. 使用互斥鎖(mutex)和條件變量(condition variable)
在多線程編程中,互斥鎖和條件變量是實(shí)現(xiàn)線程同步的常見方式。當(dāng)不同的線程需要訪問同一個共享資源時,為了避免出現(xiàn)不一致的情況,必須進(jìn)行同步。而互斥鎖和條件變量則是用來協(xié)調(diào)線程間的同步和互斥訪問。
代碼示例:
“`cpp
#include
#include
#include
#include
pthread_mutex_t mutex;
int num;
int count;
void * thread_work(void *arg)
{
int tid = *(int*)arg;
for (int i = 0; i
pthread_mutex_lock(&mutex);
num = tid;
count++;
printf(“thread #%d, num=%d, count=%d\n”, tid, num, count);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int mn()
{
pthread_t threads[16];
int ids[16];
pthread_mutex_init(&mutex, NULL);
for (int i = 0; i
ids[i] = i;
pthread_create(&threads[i], NULL, thread_work, (void*)&ids[i]);
}
for (int i = 0; i
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&mutex);
return 0;
}
“`
3. 多線程編譯優(yōu)化
在多線程編程中,編譯器對代碼進(jìn)行的優(yōu)化只是單線程編程中的一部分。但是編譯優(yōu)化涉及到包括多線程編程在內(nèi)的各種應(yīng)用,它們可以使用多種工具來幫助提高并發(fā)性能。
一些常見的編譯優(yōu)化選項(xiàng)包括:
– -O3:這個選項(xiàng)會開啟所有可能的優(yōu)化選項(xiàng),包括常量傳遞、內(nèi)聯(lián)函數(shù)、死代碼削減、函數(shù)實(shí)參優(yōu)化等等。
– -march=native:這個選項(xiàng)告訴編譯器根據(jù)系統(tǒng)內(nèi)存和CPU架構(gòu),使用它認(rèn)為更優(yōu)的指令集。
– -pthread:使用這個選項(xiàng)將會使編譯器在鏈接時啟用 pthread 庫。
三、
相關(guān)問題拓展閱讀:
- linux多線程為什么單線程執(zhí)行
linux多線程為什么單線程執(zhí)行
主要是兩個問題,
任務(wù)調(diào)度
和oversubscription。
openmp默認(rèn)使用的schedule是取決于
編譯器
實(shí)現(xiàn)的。gcc默認(rèn)使用schedule(dynamic,1),也就是動態(tài)調(diào)度并且塊大小是1。在你的程序里面,這種調(diào)度是及其低效的,看代碼都能預(yù)期到,不太可能比
單線程
快。
動態(tài)調(diào)度的一種簡單理解方式是,計(jì)算任務(wù)存在一個任務(wù)隊(duì)列里面,你的
for循環(huán)
每一個i值對應(yīng)一個計(jì)算任務(wù)。每個線程每次提取一批任務(wù),然后計(jì)算。“一批”是多少呢?就是前面說的塊大小,在你的程序里面是1。提取任務(wù)需要什么操作呢?因?yàn)檫@個任務(wù)隊(duì)列是多線程共享的,提取任務(wù)前必須加鎖,讀取一批,從隊(duì)檔梁握列中移除,然后解鎖。說到這里,你應(yīng)該已經(jīng)知道原因了。
你的線程一次只提取一次計(jì)算任務(wù),這個任務(wù)還完成得很快。然后所有的16個線程排著隊(duì),逐個去加鎖,搶任務(wù)渣局,然后解鎖讓其它線程繼續(xù)搶。然后馬上發(fā)現(xiàn)這個任務(wù)很快,又要重新去排隊(duì)等任務(wù),始終處于饑餓狀態(tài)。注意排隊(duì)的時候可能也是要占cpu的,因?yàn)槭褂昧薭usy
wait,所以可能你看來十六核滿負(fù)荷,但是其實(shí)啥也沒干。
我的建議就是,行慶使用static
schedule,或者增加dynamic
schedule的塊大小,比如1024,取決于你循環(huán)多少次。一般
如果你知道
每次循環(huán)的執(zhí)行時間基本都是一樣,并且是專用服務(wù)器設(shè)置好affinity,無其它負(fù)荷無oversubscription無numa問題的話,static
schedule會是個比較好的選擇。這樣每個線程做哪些任務(wù)只需要進(jìn)行一次分配,最小化了openmp本身的消耗。
還有一個非常重要的問題!
數(shù)值計(jì)算
不要使用
cpu超線程
!cpu的超線程對于數(shù)值計(jì)算基本是有害無益的,線程數(shù)不要大于實(shí)際核數(shù),否則就是oversubscription。你這已經(jīng)是非常嚴(yán)重的oversubscription了。數(shù)值計(jì)算專用的話,建議直接關(guān)閉服務(wù)器bios里面的超線程選項(xiàng)。
關(guān)于linux多線程服務(wù)端…的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都網(wǎng)站營銷推廣找創(chuàng)新互聯(lián),全國分站站群網(wǎng)站搭建更好做SEO營銷。
創(chuàng)新互聯(lián)(www.cdcxhl.com)四川成都IDC基礎(chǔ)服務(wù)商,價格厚道。提供成都服務(wù)器托管租用、綿陽服務(wù)器租用托管、重慶服務(wù)器托管租用、貴陽服務(wù)器機(jī)房服務(wù)器托管租用。
網(wǎng)站欄目:Linux多線程服務(wù)端編程實(shí)踐 (linux多線程服務(wù)端…)
轉(zhuǎn)載注明:http://fisionsoft.com.cn/article/copeehj.html


咨詢
建站咨詢
