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

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


咨詢
建站咨詢
