自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux高性能網(wǎng)絡(luò)編程十談 | 多進(jìn)程和多線(xiàn)程

系統(tǒng) Linux
在Linux網(wǎng)絡(luò)編程中,我們應(yīng)該見(jiàn)過(guò)很多網(wǎng)絡(luò)框架或者server,有多進(jìn)程的處理方式,也有多線(xiàn)程處理方式,孰好孰壞并沒(méi)有可比性。

在Linux網(wǎng)絡(luò)編程中,我們應(yīng)該見(jiàn)過(guò)很多網(wǎng)絡(luò)框架或者server,有多進(jìn)程的處理方式,也有多線(xiàn)程處理方式,孰好孰壞并沒(méi)有可比性,首先選擇多進(jìn)程還是多線(xiàn)程我們需要考慮業(yè)務(wù)場(chǎng)景,其次結(jié)合當(dāng)前部署環(huán)境,是云原生還是傳統(tǒng)的IDC等,最后考慮可維護(hù)性,其具體的對(duì)比在第三部分具體會(huì)展開(kāi)說(shuō)。

第一部分:多進(jìn)程

1、創(chuàng)建一個(gè)進(jìn)程

#include <unistd.h>
pid_t fork(void);
// 返回值:子進(jìn)程返回0,父進(jìn)程返回子進(jìn)程的pid,出錯(cuò)返回-1。

上面是一個(gè)創(chuàng)建進(jìn)程的函數(shù),那執(zhí)行當(dāng)前函數(shù)內(nèi)核會(huì)做哪些事情呢?

(1)如果需要?jiǎng)?chuàng)建進(jìn)程需要調(diào)用fork,進(jìn)程調(diào)用fork,當(dāng)控制轉(zhuǎn)移到內(nèi)核中的fork代碼;

(2)內(nèi)核做分配新的內(nèi)存塊和內(nèi)核數(shù)據(jù)給子進(jìn)程;

(3)內(nèi)核將父進(jìn)程部分?jǐn)?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝進(jìn)子進(jìn)程,有一部分使用寫(xiě)時(shí)復(fù)制(copy on write)和父進(jìn)程共享;

(4)添加子進(jìn)程到系統(tǒng)進(jìn)程列表中,同時(shí)父進(jìn)程打開(kāi)的文件描述符默認(rèn)在子進(jìn)程也會(huì)打開(kāi),且描述符引用計(jì)數(shù)加1;

(5)fork返回,內(nèi)核調(diào)度器開(kāi)始調(diào)度,因此fork之后,變成兩個(gè)執(zhí)行流;

2、進(jìn)程的生成周期

進(jìn)程創(chuàng)建子進(jìn)程,當(dāng)子進(jìn)程結(jié)束以后會(huì)出現(xiàn)兩種情況。

(1)如果父進(jìn)程還在,子進(jìn)程退出到父進(jìn)程讀取狀態(tài)之前,這段時(shí)間為僵尸態(tài),之后父進(jìn)程可以調(diào)用以下函數(shù)等待:

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);

// 代碼樣例
...
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { // 非阻塞等待
    ...
}
...

(2)如果父進(jìn)程不在,此時(shí)子進(jìn)程會(huì)被init進(jìn)程接管,并等待結(jié)束,如果此時(shí)子進(jìn)程一直不退出,就會(huì)一直占用內(nèi)核資源;

3、進(jìn)程間通訊

在多進(jìn)程編程模式中,各個(gè)進(jìn)程不是孤立的,需要處理進(jìn)程間通訊(IPC),如果您已經(jīng)有所了解可以一起溫故。

(1)管道

管道通訊方式在前面已經(jīng)講過(guò),通過(guò)pipe系統(tǒng)函數(shù)創(chuàng)建fd[0]和fd[1],其中兩個(gè)句柄就可以提供給父進(jìn)程和子進(jìn)程寫(xiě)入或者讀出數(shù)據(jù)。

(2)信號(hào)量

信號(hào)量是為了解決訪(fǎng)問(wèn)臨界區(qū)提供的一種特殊變量,支持兩種操作:等待和信號(hào),也就是對(duì)應(yīng)P(進(jìn)入臨界區(qū)),V(退出臨界區(qū));

假設(shè)現(xiàn)在有信號(hào)量SV,其執(zhí)行:

  • P(SV),如果SV > 0,SV將減1;如果SV == 0,掛起的當(dāng)前進(jìn)程;
  • V(SV),如果有等待SV的進(jìn)程則喚醒,如果沒(méi)有則SV將加1;

Linux系統(tǒng)API如下:

#include <sys/sem.h>

int semget(key_t key, int nums, int sem_flags);
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
int semctl(int sem_id, int sem_num, int command, ...);

semget創(chuàng)建信號(hào)量,semop操作信號(hào)量,對(duì)應(yīng)PV操作,semctl允許對(duì)信號(hào)量直接控制,為了方便大家理解,在此給一段代碼。

...
// op == -1:執(zhí)行P操作,op == 1:執(zhí)行V操作
void pv(int sem_id, int op) {
    struct sembuf sem;
    sem.sem_num = 0;
    sem.sem_op = op;
    sem,sem_flg = SEM_UNDO;
    semop(sem_id, &sem, 1);
}

int main(...) {
    int sem_id = semget(IPC_PRIVATE, 1, 0666);
    ...
    pid_t pid = fork();
    if (id == 0) {
        ... 
        pv(sem_id, -1); // 執(zhí)行P操作
        ...
        pv(sem_id, 1); // 執(zhí)行V操作
        ...
    } else {
        ... 
        pv(sem_id, -1);
        ...
        pv(sem_id, 1);
        ...
    }
}

(3)共享內(nèi)存

共享內(nèi)存是在有些場(chǎng)景下,父進(jìn)程和子進(jìn)程需要讀寫(xiě)大塊的數(shù)據(jù),因此Linux系統(tǒng)提供了shmget,shmat,shmdt,shmctl四個(gè)系統(tǒng)調(diào)用。

#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg); 
void* shmat(int shm_id, const void *shm_addr, int shmflg);
int shmdt(const void* shm_addr);
int shmctl(int shm_id, int command, struct shmid_ds* buf);

int shm_open(const char * name, int oflag, mode_t mode);
int shm_unlink(const char * name);

shmget創(chuàng)建共享內(nèi)存或者獲取已存在的共享內(nèi)存,key標(biāo)識(shí)全局唯一共享內(nèi)存,size為設(shè)置共享內(nèi)存大小,shmflg設(shè)置的一些宏;

shmat共享內(nèi)存被創(chuàng)建以后,不能直接訪(fǎng)問(wèn),需要關(guān)聯(lián)到進(jìn)程的地址空間中,可以設(shè)置shm_addr = NULL由操作系統(tǒng)選擇;

shm_open和open調(diào)用類(lèi)似,是POSIX方法,創(chuàng)建一個(gè)共享內(nèi)存對(duì)象,返回句柄與mmap調(diào)用;

shm_unlink刪除共享內(nèi)存標(biāo)記;

為了方便大家理解,在此給一段代碼:

...
shmfd = shm_open("xxxx", O_CREAT | O_RDWR, 0666);
share_mem = (char *)mmap(NULL, BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
...

注意:共享內(nèi)存需要考慮多寫(xiě)多讀的問(wèn)題,如果多個(gè)進(jìn)程寫(xiě),需要加鎖處理。

(4)消息隊(duì)列

#include <sys/msg.h>

int msgget(key_t key, int msgflg);
int msgsnd(int msgid, const void * msg_ptr, size_t msg_size, int msgflg);
int msgrcv(int msgid, void * msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgctl(int msgid, int command, struct msgid_ds * buf);

msgget創(chuàng)建消息隊(duì)列,key標(biāo)識(shí)全局唯一,msgflg和其他IPC的參數(shù)類(lèi)似;

msgsnd和msgrcv是發(fā)送和寫(xiě)入消息類(lèi)型的數(shù)據(jù);

為了方便大家理解,在此給一段代碼:

...

struct msg_buf
{
    long int msg_type;
    char text[BUFSIZ];
};
 
int main(int argc, char **argv)
{
    int msgid = -1;
    struct msg_buf data;
    long int msgtype = 0;
 
    // 建立消息隊(duì)列
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    ...
 
    // 從隊(duì)列中獲取消息
    while (1)
    {
        if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
        {
            // ...
        }
        // 遇到end結(jié)束
        if (strncmp(data.text, "end", 3) == 0)
        {
            break;
        }
    }
    // 刪除消息隊(duì)列
    if (msgctl(msgid, IPC_RMID, 0) == -1)
    {
        ...
    }
    ...
}

(5)UNIX域

除了以上的通用的IPC,socket的UNIX域也可以作為進(jìn)程間通訊,比如使用socket(AF_UNIX, SOCK_STREAM, 0),或socketpair系統(tǒng)調(diào)用,或父進(jìn)程創(chuàng)建一個(gè)127.0.0.1環(huán)回接口socket server,子進(jìn)程通過(guò)socket client訪(fǎng)問(wèn)。

4、如何在網(wǎng)絡(luò)編程中使用多進(jìn)程

在多進(jìn)程的網(wǎng)絡(luò)編程中,實(shí)現(xiàn)方式有很多,但是總體還是圍繞兩條線(xiàn),其一如何將新建連接分發(fā)給子進(jìn)程,其二如何將數(shù)據(jù)/信號(hào)傳給子進(jìn)程,并監(jiān)控子進(jìn)程,下圖是其實(shí)現(xiàn)方式之一(由于實(shí)現(xiàn)細(xì)節(jié)很多,后續(xù)會(huì)將實(shí)現(xiàn)代碼開(kāi)源到github):

多進(jìn)程多進(jìn)程

(1)首先為了性能考慮,進(jìn)程池是必須的,通過(guò)線(xiàn)程池不需要頻繁創(chuàng)建和銷(xiāo)毀進(jìn)程;

(2)其次主進(jìn)程accept對(duì)應(yīng)的新連接,考慮各個(gè)進(jìn)程之間負(fù)載均衡,將新連接通過(guò)隨機(jī)算法分發(fā)給子進(jìn)程;

(3)分發(fā)方式可以通過(guò)管道,共享內(nèi)存,消息隊(duì)列等方式告知子進(jìn)程,也可以傳遞數(shù)據(jù)信息;

(4)子進(jìn)程收到新連接的句柄,就可以通過(guò)內(nèi)部的epoll監(jiān)聽(tīng)I(yíng)O事件,從而完成send和recv;

第二部分:多線(xiàn)程

1、概述

在Linux中,線(xiàn)程是輕量級(jí)進(jìn)程,運(yùn)行在內(nèi)核空間,由內(nèi)核調(diào)度,最開(kāi)始的線(xiàn)程庫(kù)是linuxThreads,但是linuxThreads不符合POSIX標(biāo)準(zhǔn),后來(lái)出現(xiàn)了NGPT和NPTL,其采用的線(xiàn)程模型不一樣,所以性能有差異,性能由快到慢是:NPTL > NGPT > linuxThreads。

其中線(xiàn)程的模型分為三種:

  • 多對(duì)一(M:1)的用戶(hù)級(jí)線(xiàn)程模型;
  • 一對(duì)一(1:1)的內(nèi)核級(jí)線(xiàn)程模型:如linuxThreads和NPTL;
  • 多對(duì)多(M:N)的兩極線(xiàn)程模型:如NGPT;

現(xiàn)在Linux的2.6內(nèi)核版本開(kāi)始,默認(rèn)使用NPTL線(xiàn)程庫(kù)(1:1的線(xiàn)程模型),對(duì)比linuxThreads有如下優(yōu)勢(shì):

  • 內(nèi)核線(xiàn)程不再是一個(gè)進(jìn)程,因此避免用進(jìn)程模擬線(xiàn)程導(dǎo)致的語(yǔ)義問(wèn)題;
  • 摒棄了管理線(xiàn)程,終止線(xiàn)程和回收線(xiàn)程等工作由內(nèi)核完成;
  • 一個(gè)進(jìn)程中的線(xiàn)程可以運(yùn)行在不同的CPU上,可以充分利用多處理器系統(tǒng);
  • 線(xiàn)程的同步由內(nèi)核完成,隸屬于不同的進(jìn)程的線(xiàn)程之間也可以共享互斥鎖,因此可以實(shí)現(xiàn)跨進(jìn)程的線(xiàn)程同步;

2、線(xiàn)程API

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
void pthread_exit(void *retval);
int pthread_join(pthread_t thread, void **retval);
int pthread_cancel(pthread_t thread);
int pthread_detach(pthread_t thread);
pthread_t pthread_self();

(1)pthread_create創(chuàng)建線(xiàn)程,thread表示線(xiàn)程ID,attr表示設(shè)置線(xiàn)程屬性,另外傳遞線(xiàn)程處理函數(shù)start_routine和參數(shù)arg;

(2)pthread_exit線(xiàn)程退出,可以在start_routine執(zhí)行完成以后調(diào)用;

(3)pthread_join是等待線(xiàn)程結(jié)束,調(diào)用成功返回0,否則返回錯(cuò)誤;

(4)pthread_cancel異常終止一個(gè)線(xiàn)程;

(5)pthread_detach把指定的線(xiàn)程轉(zhuǎn)變?yōu)槊撾x狀態(tài),線(xiàn)程有兩種屬性,一種是joinable,一種是detached,當(dāng)一個(gè)joinable線(xiàn)程終止時(shí),它的線(xiàn)程ID和退出狀態(tài)將留存到另一個(gè)線(xiàn)程對(duì)它調(diào)用pthread_join,調(diào)用前線(xiàn)程的資源不會(huì)釋放,而脫離detached線(xiàn)程終止時(shí),資源會(huì)立刻釋放;

(6)pthread_self獲取當(dāng)前線(xiàn)程ID;

為了方便大家理解,在此給一段代碼(使用c++11語(yǔ)法,底層是以上API的封裝):

#include<iostream>
#include<pthread.h>
#include<thread>

void func(void *arg)
{
    std::cout << "threadid: " << pthread_self() << ", arg: " << *(int*)arg << std::endl;
}

int main()
{
    int i = 1;
    std::thread t1(func, &i);
    t1.join();

    ++i;
    std::thread t2(func, &i);
    t2.join();    
}

3、線(xiàn)程間通訊

(1)信號(hào)量

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destory(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);

這里的API和多進(jìn)程的信號(hào)量類(lèi)似,就不展開(kāi)詳細(xì)說(shuō)了,其中PV操作對(duì)應(yīng)的函數(shù)是sem_wait信號(hào)量減1,sem_post信號(hào)量加1;

(2)互斥鎖

互斥鎖是線(xiàn)程獨(dú)占臨界區(qū)的控制方式,通過(guò)以下系統(tǒng)API:

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_destory(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_init是鎖mutex的初始化,mutexattr為設(shè)置鎖屬性,主要是類(lèi)型:

  • PTHREAD_MUTEX_NORMAL普通鎖,只能在同一個(gè)線(xiàn)程加鎖解鎖,但是加鎖不可重入,其他線(xiàn)程不能解鎖當(dāng)前線(xiàn)程的鎖,否則會(huì)導(dǎo)致死鎖或者不可預(yù)期效果;
  • PTHREAD_MUTEX_ERRORCHECK糾錯(cuò)鎖,主要提供錯(cuò)誤檢查;
  • PTHREAD_MUTEX_RECURSIVE嵌套鎖,允許同一個(gè)線(xiàn)程重入加鎖,不過(guò)其他線(xiàn)程需要這個(gè)鎖,當(dāng)前鎖的擁有者需要執(zhí)行相應(yīng)次數(shù)的解鎖,對(duì)已經(jīng)被其他線(xiàn)程加鎖的嵌套鎖解鎖或者對(duì)已經(jīng)解鎖的嵌套鎖再解鎖,都會(huì)返回錯(cuò)誤;
  • PTHREAD_MUTEX_DEFAULT默認(rèn)鎖,多次加鎖解鎖等行為是未定義;

pthread_mutex_lock與pthread_mutex_unlock成對(duì)出現(xiàn),這里要注意的是對(duì)于非嵌套鎖,一定要注意死鎖場(chǎng)景,另外不要對(duì)pthread_mutex_destory執(zhí)行后的鎖再執(zhí)行加鎖或者解鎖操作;

(3)條件變量

條件變量是一種線(xiàn)程間通訊機(jī)制,當(dāng)某個(gè)共享數(shù)據(jù)達(dá)到某個(gè)值得時(shí)候,喚醒等待該數(shù)據(jù)的線(xiàn)程繼續(xù)執(zhí)行,其API如下:

#include <pthread.h>

int pthread_cond_init(pthread_cont_t *cond, const pthread_contattr_t* cond_attr);
int pthread_cond_destory(pthread_cont_t *cond);
int pthread_cond_broadcast(pthread_cont_t *cond);
int pthread_cond_signal(pthread_cont_t *cond);
int pthread_cond_wait(pthread_cont_t *cond, pthread_mutex_t* mutex);

pthread_cond_init初始化條件變量cond,pthread_cond_destory銷(xiāo)毀條件變量和釋放占用內(nèi)核資源,pthread_cond_broadcast廣播喚醒所有等待cond的線(xiàn)程;

pthread_cond_signal喚醒一個(gè)等待cond的線(xiàn)程,至于哪個(gè)被喚醒,取決于線(xiàn)程優(yōu)先級(jí)和調(diào)度策略;

其中以上兩個(gè)等待的函數(shù)是pthread_cond_wait,可能大家有點(diǎn)奇怪,為啥pthread_cond_wait需要帶一個(gè)鎖呢?這是mutex確保pthread_cond_wait操作的原子性,調(diào)用pthread_cond_wait之前需要將mutex加鎖,pthread_cond_wait執(zhí)行時(shí)候,首先會(huì)把調(diào)用線(xiàn)程放入條件變量的等待隊(duì)列中,然后將mutex解鎖,等pthread_cond_wait返回成功后,對(duì)mutex繼續(xù)加鎖,后續(xù)處理交給各自線(xiàn)程;

4、如何在網(wǎng)絡(luò)編程中使用多線(xiàn)程

與多進(jìn)程對(duì)比,多線(xiàn)程的處理方式相對(duì)就簡(jiǎn)單很多,由于在多線(xiàn)程內(nèi)部數(shù)據(jù)是共享的,所以沒(méi)有繁瑣的數(shù)據(jù)傳遞,只需要隊(duì)列就可以完成主線(xiàn)程和子線(xiàn)程之間的數(shù)據(jù)通信,下圖是其實(shí)現(xiàn)方式之一(由于實(shí)現(xiàn)細(xì)節(jié)很多,后續(xù)會(huì)將實(shí)現(xiàn)代碼開(kāi)源到github):

多線(xiàn)程多線(xiàn)程

(1)和進(jìn)程一樣,為了性能考慮,線(xiàn)程池是必須的,這樣對(duì)于IO密集型場(chǎng)景,處理線(xiàn)程一般是跑不滿(mǎn)的;

(2)主線(xiàn)程accept對(duì)應(yīng)的新連接,將新連接插入queue,同時(shí)通過(guò)信號(hào)量或條件變量或互斥鎖告知線(xiàn)程池中的線(xiàn)程;

(3)線(xiàn)程池的線(xiàn)程收到通知,先開(kāi)始搶鎖,然后從隊(duì)列中取出新連接;

(4)子線(xiàn)程拿到新連接的句柄,就可以通過(guò)內(nèi)部的epoll監(jiān)聽(tīng)I(yíng)O事件,從而完成send和recv;

第三部分:多進(jìn)程和多線(xiàn)程之爭(zhēng)

在云原生時(shí)代之前,多進(jìn)程和多線(xiàn)程的網(wǎng)絡(luò)框架的爭(zhēng)論已久,每個(gè)開(kāi)發(fā)者選擇都有自己的考慮,比如多進(jìn)程代表的web server是Nginx,Apache等,多線(xiàn)程的有Varnish,gRPC,libevent庫(kù)等等,到底該如何選擇網(wǎng)絡(luò)框架呢?

(1)首先結(jié)合最大化利用多個(gè)處理器的硬件結(jié)構(gòu)和軟件架構(gòu),在大多數(shù)情況下,選擇多線(xiàn)程或多進(jìn)程處理,又或者兩者兼用都能實(shí)現(xiàn),但是這個(gè)選擇將影響軟件的性能、后期的維護(hù)、可擴(kuò)展性、內(nèi)存等各方面,所以開(kāi)發(fā)網(wǎng)絡(luò)框架之前一定要綜合考慮;

(2)考慮多線(xiàn)程的優(yōu)缺點(diǎn):

  • 優(yōu)點(diǎn):多線(xiàn)程最突出的優(yōu)點(diǎn)是借助變量、對(duì)象等,線(xiàn)程之間可以便捷地共享數(shù)據(jù),與主線(xiàn)程進(jìn)行通信也非常容易;在內(nèi)核部分方面,運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線(xiàn)程,它們彼此之間使用相同的地址空間,啟動(dòng)一個(gè)線(xiàn)程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動(dòng)一個(gè)進(jìn)程所花費(fèi)的空間,而且,線(xiàn)程間彼此切換所需的時(shí)間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時(shí)間;
  • 缺點(diǎn):如果其中一個(gè)線(xiàn)程崩潰,整個(gè)應(yīng)用程序?qū)⑦B帶崩潰;在調(diào)試代碼方面,多線(xiàn)程調(diào)試非常困難,往往很多意想不到的bug都是多線(xiàn)程操作不當(dāng)產(chǎn)生,但是看日志又可能看不出來(lái);在內(nèi)核部分多線(xiàn)程可能導(dǎo)致花費(fèi)大量時(shí)間進(jìn)行上下文切換,影響性能,比如監(jiān)聽(tīng)socket后,多個(gè)線(xiàn)程同時(shí)搶占鎖導(dǎo)致頻繁切換,同時(shí)每個(gè)線(xiàn)程與主程序共用地址空間,線(xiàn)程內(nèi)存受限于進(jìn)程內(nèi)存空間;還有一個(gè)最大的問(wèn)題就是寫(xiě)代碼過(guò)程中,必須要考慮鎖的情況,如操作全局變量,臨界區(qū)數(shù)據(jù)等等,往往使代碼的結(jié)構(gòu)比較復(fù)雜;

(3)考慮多進(jìn)程的優(yōu)缺點(diǎn):

  • 優(yōu)點(diǎn):一個(gè)進(jìn)程崩潰,并不意味著整個(gè)應(yīng)用程序的崩潰,這是多進(jìn)程開(kāi)發(fā)的一個(gè)顯著優(yōu)勢(shì)(內(nèi)核空間進(jìn)程除外);調(diào)試方便,可以快速?gòu)娜罩净蛘遟db跟進(jìn)當(dāng)前進(jìn)程的運(yùn)行狀態(tài);寫(xiě)代碼需要考慮的鎖更少,比如操作全局變量或者臨界區(qū),使得代碼的整體結(jié)構(gòu)相對(duì)簡(jiǎn)單;
  • 缺點(diǎn):進(jìn)程之間的通信或者通知比線(xiàn)程之間復(fù)雜,需要使用到IPC各種方式;在內(nèi)核層面,進(jìn)程越多對(duì)于內(nèi)核調(diào)度會(huì)越慢,導(dǎo)致整體性能下降;雖然上面優(yōu)點(diǎn)里面對(duì)于進(jìn)程崩潰更好容錯(cuò),但是多個(gè)進(jìn)程運(yùn)行狀態(tài),需要主進(jìn)程監(jiān)聽(tīng)或者周邊程序監(jiān)控,使維護(hù)功能增多;

以上的考慮是基于云原生時(shí)代之前,隨著容器化的到來(lái),我們應(yīng)遵循"每個(gè)容器一個(gè)應(yīng)用程序"的原則,原因如下:

  • 每個(gè)容器中只運(yùn)行一個(gè)應(yīng)用程序,則水平伸縮將變得十分容易;
  • 每個(gè)容器中只運(yùn)行一個(gè)應(yīng)用程序,升級(jí)程序時(shí)能夠?qū)⒂绊懛秶刂圃俑〉牧6?,極大增加應(yīng)用程序生命周期管理的靈活性,避免在升級(jí)某個(gè)服務(wù)時(shí)中斷相同容器中的其他進(jìn)程;
  • 每個(gè)容器中只運(yùn)行一個(gè)應(yīng)用程序,可以更好的利用云原生的工具,比如監(jiān)控,探測(cè)等;

以上是結(jié)合知乎大佬們的實(shí)踐和我個(gè)人的工程實(shí)踐一些總結(jié),僅供參考。實(shí)際選擇和開(kāi)發(fā)過(guò)程中,希望開(kāi)發(fā)者更多結(jié)合業(yè)務(wù)場(chǎng)景來(lái)選擇和設(shè)計(jì)網(wǎng)絡(luò)框架。

思考

從整篇文章讀下來(lái),讀者應(yīng)該已經(jīng)系統(tǒng)性的了解了多進(jìn)程和多線(xiàn)程,老規(guī)矩那就提幾個(gè)思考題(下一章會(huì)解答當(dāng)前問(wèn)題):

(1)如果在多線(xiàn)程程序中fork()子進(jìn)程,會(huì)發(fā)生什么,我們要考慮那些問(wèn)題?

(2)在多線(xiàn)程程序中,某個(gè)線(xiàn)程掛了,整個(gè)進(jìn)程會(huì)掛么?

(3)如果需要將進(jìn)程信號(hào)發(fā)送給某個(gè)線(xiàn)程,該如何處理?

責(zé)任編輯:華軒 來(lái)源: 周末程序猿
相關(guān)推薦

2024-03-18 13:43:20

Linux架構(gòu)

2023-11-01 11:59:13

2023-11-01 10:38:46

Linux高性能網(wǎng)絡(luò)編程

2023-11-01 10:58:31

系統(tǒng)調(diào)用高性能網(wǎng)絡(luò)編程Linux

2023-11-01 11:40:46

Linux高性能網(wǎng)絡(luò)編程工具

2023-11-01 11:51:08

Linux性能優(yōu)化

2023-11-01 11:27:10

Linux協(xié)程

2023-11-01 11:07:05

Linux高性能網(wǎng)絡(luò)編程線(xiàn)程

2023-11-01 11:13:58

Linux信號(hào)處理定時(shí)器

2023-11-01 10:43:31

Linux高性能網(wǎng)絡(luò)編程

2023-12-11 18:18:24

Python編程線(xiàn)程

2024-10-06 14:37:52

2016-10-09 20:15:30

多線(xiàn)程多進(jìn)程

2019-02-26 11:15:25

進(jìn)程多線(xiàn)程多進(jìn)程

2022-03-09 17:01:32

Python多線(xiàn)程多進(jìn)程

2021-06-11 06:54:35

PythonThreadingMultiproces

2021-04-20 12:39:52

Node.js多線(xiàn)程多進(jìn)程

2021-08-04 23:30:28

Node.js開(kāi)發(fā)線(xiàn)程

2010-07-26 09:45:09

Perl多進(jìn)程

2023-12-13 09:56:13

?多進(jìn)程多線(xiàn)程協(xié)程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)