溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

發(fā)布時(shí)間:2021-11-01 10:01:35 來(lái)源:億速云 閱讀:122 作者:柒染 欄目:系統(tǒng)運(yùn)維

這篇文章給大家介紹Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

我其實(shí)并不想討論微內(nèi)核的概念,也并不擅長(zhǎng)去闡述概念,這是百科全書(shū)的事,但無(wú)奈最近由于鴻蒙的發(fā)布導(dǎo)致這個(gè)話題過(guò)火,也就經(jīng)不住誘惑,加上我又一直比較喜歡操作系統(tǒng)這個(gè)話題,就來(lái)個(gè)老生常談吧。

說(shuō)起微內(nèi)核,其性能往往因?yàn)镮PC飽受詬病。然而除了這個(gè)顯而易見(jiàn)的 “缺陷” ,其它方面貌似被關(guān)注的很少。因此我寫(xiě)點(diǎn)稍微不同的。

微內(nèi)核的性能 “缺陷” 我假設(shè)是高開(kāi)銷的IPC引起的(實(shí)際上也真是),那么,我接下來(lái)便繼續(xù)假設(shè)這個(gè)IPC性能是可以優(yōu)化的,并且它已經(jīng)被優(yōu)化(即便不做任何事,隨著硬件技術(shù)的發(fā)展,所謂的歷史缺點(diǎn)往往也將逐漸弱化...)。我不公道地回避了核心問(wèn)題,這并不是很道德,但為了下面的行文順利,我不得不這么做。

很多人之所以并不看好微內(nèi)核,很大程度上是因?yàn)樗蚅inux內(nèi)核是如此不同,人們認(rèn)為不同于Linux內(nèi)核的操作系統(tǒng)內(nèi)核都有這樣那樣的缺陷,這是因?yàn)長(zhǎng)inux內(nèi)核給我們洗了腦。

Linux內(nèi)核的設(shè)計(jì)固化了人們對(duì)操作系統(tǒng)內(nèi)核的理解上的觀念 ,以至于 Linux內(nèi)核做什么都是對(duì)的,反Linux的大概率是錯(cuò)的。 Linux內(nèi)核就一定正確嗎?

在我看來(lái),Linux內(nèi)核只是在恰當(dāng)?shù)臅r(shí)間出現(xiàn)的一個(gè)恰好能跑的內(nèi)核,并且恰好它是開(kāi)源的,讓人們可以第一次內(nèi)窺一個(gè)操作系統(tǒng)內(nèi)核的全貌罷了,這并不意味著它就一定是正確的。相反,它很可能是錯(cuò)誤的。【 20世紀(jì)90年代,Windows NT系統(tǒng)初始,但很難看到它的內(nèi)在,《windows internal》風(fēng)靡一時(shí);UNIX陷入糾紛,GNU呼之卻不出,此時(shí)Linux內(nèi)核滿足了人們一切的好奇心,于是先入為主,讓人們覺(jué)的操作系統(tǒng)就應(yīng)該是這個(gè)樣子,并且在大多數(shù)人看來(lái),這是它唯一的相貌。 】

本文主要說(shuō) 內(nèi)核的可擴(kuò)展性 。

先潑一盆冷水,Linux內(nèi)核在這方面做得并非已經(jīng)爐火純青。

誠(chéng)然,近十幾年來(lái)Linux內(nèi)核從2.6發(fā)展到5.3,一直在SMP多核擴(kuò)展方面精益求精,但是說(shuō)實(shí)話架構(gòu)上并沒(méi)有什么根本性的調(diào)整,要說(shuō)比較大的調(diào)整,當(dāng)屬:

  •  $O(1)$調(diào)度算法。

  •  SMP處理器域負(fù)載均衡算法。

  •  percpu數(shù)據(jù)結(jié)構(gòu)。

  •  數(shù)據(jù)結(jié)構(gòu)拆鎖。

都是一些細(xì)節(jié),沒(méi)有什么讓人哇塞的東西,還有更細(xì)節(jié)的cache刷新的管理,這種第二天不用就忘記的東西,引多少人競(jìng)折腰。

這不禁讓人想起在交換式以太網(wǎng)出現(xiàn)之前,人們不斷優(yōu)化CSMA/CD算法的過(guò)程,同樣沒(méi)有讓人哇塞,直到交換機(jī)的出現(xiàn),讓人眼前一亮,CSMA/CD隨之幾乎被完全廢棄,因?yàn)樗皇?正確 的東西。

交換機(jī)之所以 正確 的核心在于 仲裁。

當(dāng)一個(gè)共享資源每次只能容納一個(gè)實(shí)體占用訪問(wèn)時(shí),我們稱該資源為 “必須串行訪問(wèn)的共享資源” ,當(dāng)有多個(gè)實(shí)體均意欲訪問(wèn)這種資源時(shí),one by one是必然的,one by one的方案有兩種:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

哪個(gè)好?說(shuō)說(shuō)看。

爭(zhēng)搶必會(huì)產(chǎn)生沖突,沖突便耽誤整體通過(guò)的時(shí)間,你會(huì)選哪個(gè)?

現(xiàn)在,我們暫時(shí)忘掉諸如宏內(nèi)核,微內(nèi)核,進(jìn)程隔離,進(jìn)程切換,cache刷新,IPC等概念,這些概念對(duì)于我們理解事情的本質(zhì)毫無(wú)幫助,相反,它們會(huì)阻礙我們建立新的認(rèn)知。比如,無(wú)論你覺(jué)得微內(nèi)核多么好,總有人跳出來(lái)說(shuō)IPC是微內(nèi)核的瓶頸,當(dāng)你提出一個(gè)類似頁(yè)表項(xiàng)交換等優(yōu)化后,又會(huì)有人說(shuō)進(jìn)程切換刷cache,寄存器上下文save/restore的開(kāi)銷也不小,然后你可能知道點(diǎn) 帶有進(jìn)程PID鍵值的cache方案 ,吧啦吧啦,最后一個(gè)show me the code 讓你無(wú)言以對(duì),一來(lái)二去,還沒(méi)有認(rèn)識(shí)全貌,便已經(jīng)陷入了細(xì)節(jié)。

所以,把這些忘掉,來(lái)看一個(gè)觀點(diǎn):

  •  對(duì)待必須串行訪問(wèn)的共享資源,正確的做法是引入一個(gè)仲裁者排隊(duì)調(diào)度訪問(wèn)者,而不是任由訪問(wèn)者們?nèi)ゲl(fā)爭(zhēng)鎖!

所謂 操作系統(tǒng) 這個(gè)概念,本來(lái)就是莫須有的,你可以隨便叫它什么,早期它叫 監(jiān)視器 ,現(xiàn)在我們姑且就叫它操作系統(tǒng)吧,但這并不意味著這個(gè)概念有多么神奇。

操作系統(tǒng)本就是用來(lái)協(xié)調(diào)多個(gè)進(jìn)程(這也是個(gè)抽象后的概念,你叫它任務(wù)也可以,無(wú)所謂)對(duì)底層共享資源的 多對(duì)一訪問(wèn) 的,最典型的資源恐怕就是CPU資源了,而幾乎所有人都知道,CPU資源是需要調(diào)度使用的,于是任務(wù)調(diào)度一直都是一個(gè)熱門(mén)話題。

你看, CPU就不是所有任務(wù)并發(fā)爭(zhēng)搶使用的,而是調(diào)度器讓誰(shuí)用誰(shuí)才能用 。調(diào)度,或者說(shuō)仲裁,這是操作系統(tǒng)的精髓。

那么對(duì)于系統(tǒng)中共享的文件,socket,對(duì)于各種表比如路由表等資源,憑什么要用并發(fā)爭(zhēng)搶的方式去使用?!所有的共享資源,都應(yīng)該是被調(diào)度使用的,就像CPU資源一樣。

如果我們循著操作系統(tǒng)理應(yīng)實(shí)現(xiàn)的最本質(zhì)的功能去思考,而不是以Linux作為先入為主的標(biāo)準(zhǔn)去思考,會(huì)發(fā)現(xiàn)Linux內(nèi)核處理并發(fā)明顯是一種錯(cuò)誤的方式!

Linux內(nèi)核大量使用了自旋鎖,這明顯是從單核向SMP進(jìn)化時(shí)最最最簡(jiǎn)單的方案,即 只要保證不出問(wèn)題的方案!

也確實(shí)如此,單核上的自旋鎖并不能如其字面表達(dá)的那樣 自旋 , 在單核場(chǎng)景下,Linux的自旋鎖實(shí)現(xiàn)僅僅是 禁用了搶占 。因?yàn)?,這樣即可保證 不出問(wèn)題 。

但到了必須要支持SMP的時(shí)候,簡(jiǎn)單的禁用搶占已經(jīng)無(wú)法保證不出問(wèn)題,所以 待在原地自旋等待持鎖者離開(kāi) 便成了最顯而易見(jiàn)的方案。自旋鎖就這樣一直用到了現(xiàn)在。一直到今天,自旋鎖在不斷被優(yōu)化,然而無(wú)論怎么優(yōu)化,它始終都是一個(gè)不合時(shí)宜的自旋鎖。

可見(jiàn),Linux內(nèi)核一開(kāi)始就不是為SMP設(shè)計(jì)的,因此其并發(fā)模式是錯(cuò)誤的,至少不是合適的。

有破就要有立,我下面將用一套用戶態(tài)的代碼來(lái)模擬 無(wú)仲裁的宏內(nèi)核 以及 有仲裁的微內(nèi)核 分別是如何對(duì)待共享資源訪問(wèn)的。代碼比較簡(jiǎn)單,所以我就沒(méi)加入太多的注釋。

以下的代碼模擬宏內(nèi)核中訪問(wèn)共享資源時(shí)的自旋鎖并發(fā)爭(zhēng)搶模式:

#include <pthread.h>  #include <signal.h>  #include <stdio.h>  #include <unistd.h>  #include <stdlib.h> #include <errno.h>  #include <sys/time.h>  static int count = 0;  static int curr = 0;  static pthread_spinlock_t spin;  long long end, start;  int timer_start = 0;  int timer = 0;  long long gettime()  {      struct timeb t;      ftime(&t);      return 1000 * t.time + t.millitm;  }  void print_result()  {      printf("%d\n", curr);      exit(0);  }  struct node {      struct node *next;      void *data;  };  void do_task() {      int i = 0, j = 2, k = 0;      // 為了更加公平的對(duì)比,既然模擬微內(nèi)核的代碼使用了內(nèi)存分配,這里也fake一個(gè)。      struct node *tsk = (struct node*) malloc(sizeof(struct node));      pthread_spin_lock(&spin); // 鎖定整個(gè)訪問(wèn)計(jì)算區(qū)間      if (timer && timer_start == 0) {           struct itimerval tick = {0};          timer_start = 1;          signal(SIGALRM, print_result);          tick.it_value.tv_sec = 10;          tick.it_value.tv_usec = 0;          setitimer(ITIMER_REAL, &tick, NULL);      }      if (!timer && curr == count) {          end = gettime();          printf("%lld\n", end - start);          exit(0);      }      curr ++;      for (i = 0; i < 0xff; i++) { // 做一些稍微耗時(shí)的計(jì)算,模擬類似socket操作。強(qiáng)度可以調(diào)整,比如0xff->0xffff,CPU比較猛比較多的機(jī)器上做測(cè)試,將其調(diào)強(qiáng)些,否則隊(duì)列開(kāi)銷會(huì)淹沒(méi)模擬任務(wù)的開(kāi)銷。          k += i/j;      }      pthread_spin_unlock(&spin);      free(tsk);  }  void* func(void *arg)  {      while (1) {          do_task();      }  }  int main(int argc, char **argv)  {      int err, i;      int tcnt;      pthread_t tid;      count = atoi(argv[1]);      tcnt = atoi(argv[2]);      if (argc == 4) {          timer = 1;      }      pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);      start = gettime();      // 創(chuàng)建工作線程      for (i = 0; i < tcnt; i++) {          err = pthread_create(&tid, NULL, func, NULL);          if (err != 0) {              exit(1);          }      }      sleep(3600);      return 0;  }

相對(duì)的,微內(nèi)核采用將請(qǐng)求通過(guò)IPC發(fā)送到專門(mén)的服務(wù)進(jìn)程,模擬代碼如下: 

#include <pthread.h>      #include <signal.h>      #include <stdio.h>      #include <unistd.h>      #include <stdlib.h>      #include <errno.h>      #include <sys/time.h>     static int count = 0;      static int curr = 0;      long long end, start;     int timer = 0;     int timer_start = 0;      static int total = 0;      long long gettime()      {          struct timeb t;          ftime(&t);          return 1000 * t.time + t.millitm;      }      struct node {          struct node *next;          void *data;      };      void print_result()      {          printf("%d\n", total);          exit(0);      }      struct node *head = NULL;      struct node *current = NULL;      void insert(struct node *node)      {          node->data = NULL;          node->next = head;          head = node;      }      struct node* delete()      {          struct node *tempLink = head;          headhead = head->next;          return tempLink;      }      int empty()      {          return head == NULL;      }      static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;      static pthread_spinlock_t spin;      int add_task()      {          struct node *tsk = (struct node*) malloc(sizeof(struct node));          pthread_spin_lock(&spin);          if (timer || curr < count) {              curr ++;              insert(tsk);          }          pthread_spin_unlock(&spin);          return curr;      }      // 強(qiáng)度可以調(diào)整,比如0xff->0xffff,CPU比較猛比較多的機(jī)器上做測(cè)試,將其調(diào)強(qiáng)些,否則隊(duì)列開(kāi)銷會(huì)淹沒(méi)模擬任務(wù)的開(kāi)銷。      void do_task()      {           int i = 0, j = 2, k = 0;          for (i = 0; i < 0xff; i++) {              k += i/j;          }      }     void* func(void *arg)      {          int ret;          while (1) {              ret = add_task();              if (!timer && ret == count) {                  break;              }          }     }      void* server_func(void *arg)      {          while (timer || total != count) {              struct node *tsk;              pthread_spin_lock(&spin);              if (empty()) {                  pthread_spin_unlock(&spin);                  continue;              }              if (timer && timer_start == 0) {                  struct itimerval tick = {0};                  timer_start = 1;                 signal(SIGALRM, print_result);                  tick.it_value.tv_sec = 10;                  tick.it_value.tv_usec = 0;                 setitimer(ITIMER_REAL, &tick, NULL);              }              tsk = delete();              pthread_spin_unlock(&spin);              do_task();              free(tsk);              total++;          }          end = gettime();          printf("%lld   %d\n", end - start, total);          exit(0);      }      int main(int argc, char **argv)      {          int err, i;          int tcnt;          pthread_t tid, stid;          count = atoi(argv[1]);          tcnt = atoi(argv[2]);          if (argc == 4) {              timer = 1;          }         pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);          // 創(chuàng)建服務(wù)線程          err = pthread_create(&stid, NULL, server_func, NULL);          if (err != 0) {              exit(1);          }          start = gettime();          // 創(chuàng)建工作線程          for (i = 0; i < tcnt; i++) {              err = pthread_create(&tid, NULL, func, NULL);              if (err != 0) {                  exit(1);              }          }          sleep(3600);          return 0;      }

我們對(duì)比一下執(zhí)行同樣多的任務(wù),在不同的線程數(shù)的約束下,兩種模式的時(shí)間開(kāi)銷對(duì)比圖:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

我們看到,在模擬微內(nèi)核的代碼中,用多線程執(zhí)行并行訪問(wèn)共享數(shù)據(jù)curr時(shí),開(kāi)銷不會(huì)隨著線程數(shù)量的變化而變化,而模擬宏內(nèi)核的代碼中,總時(shí)間隨著線程數(shù)的增加而線性增加,顯然,這部分開(kāi)銷是自旋鎖的開(kāi)銷。當(dāng)今流行的CPU cache結(jié)構(gòu)已經(jīng)排隊(duì)自旋鎖的開(kāi)銷符合這種線性增長(zhǎng)。

那么為什么微內(nèi)核的模擬代碼中的鎖開(kāi)銷沒(méi)有隨著線程數(shù)量的增加而增加呢?

因?yàn)樵陬愃坪陜?nèi)核的同步任務(wù)中,由于并發(fā)上下文的相互隔離,整個(gè)任務(wù)必須被一個(gè)鎖保護(hù),比如 Linux內(nèi)核的tcp_v4_rcv 里面的:     

bh_lock_sock_nested(sk);         // 這部分耗時(shí)時(shí)間不確定,因此CPU空轉(zhuǎn)率不確定,低效,浪費(fèi)!         ret = 0;        if (!sock_owned_by_user(sk)) {             if (!tcp_prequeue(sk, skb))                ret = tcp_v4_do_rcv(sk, skb);         } else if (unlikely(sk_add_backlog(sk, skb,                            sk->sk_rcvbuf + sk->sk_sndbuf))) {             bh_unlock_sock(sk);             NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);             goto discard_and_relse;         }         bh_unlock_sock(sk);

然而,在微內(nèi)核的代碼中,類似上面的任務(wù)被打包統(tǒng)一交給單獨(dú)的服務(wù)線程去 調(diào)度執(zhí)行 了,大大減少了鎖區(qū)里的延時(shí)。

宏內(nèi)核的隔離上下文并發(fā)搶鎖場(chǎng)景需要鎖整個(gè)任務(wù),造成搶鎖開(kāi)銷巨大,而微內(nèi)核只要鎖任務(wù)隊(duì)列的入隊(duì)出隊(duì)操作即可,這部分開(kāi)銷和具體任務(wù)無(wú)關(guān),完全可預(yù)期的開(kāi)銷。

接下來(lái)讓我們對(duì)比一下執(zhí)行同樣的任務(wù),在不同CPU數(shù)量的約束下,兩種模式的時(shí)間開(kāi)銷對(duì)比圖:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

可見(jiàn),隨著CPU數(shù)量的增加,模擬宏內(nèi)核的代碼鎖開(kāi)銷大致在線性增加,而模擬微內(nèi)核的代碼,鎖開(kāi)銷雖然也有所增加,但顯然并不明顯。

為什么會(huì)這樣?請(qǐng)看下面宏內(nèi)核和微內(nèi)核的對(duì)比圖,先看宏內(nèi)核:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

再看微內(nèi)核:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

這顯然是一種更加 現(xiàn)代 的方式,不光是減小了鎖的開(kāi)銷提高了性能,更重要的是大大減少了CPU的空轉(zhuǎn),提高了CPU的利用率。

我們先看一下模擬宏內(nèi)核的代碼在執(zhí)行10秒時(shí)的CPU利用率:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

觀察下熱點(diǎn),可以猜測(cè)就是spinlock:

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

顯然,CPU利用率那么高,并非真的在執(zhí)行有用的task,而是在spin空轉(zhuǎn)。

我們?cè)倏聪履M微內(nèi)核的代碼在同樣情況下的表現(xiàn):

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

看下熱點(diǎn):

Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足

顯然,仍然有個(gè)spinlock的熱點(diǎn),但顯然降低了很多。在更高執(zhí)行效率的保證下,CPU并沒(méi)有那么高,剩余的空閑時(shí)間可以再去執(zhí)行更多有意義的工作進(jìn)程。

本文只是展示一個(gè)定性的效果,實(shí)際中,微內(nèi)核服務(wù)進(jìn)程的任務(wù)隊(duì)列的管理效率會(huì)更高。甚至可以硬件實(shí)現(xiàn)。【參見(jiàn)交換機(jī)背板的交換網(wǎng)絡(luò)實(shí)現(xiàn)。】

說(shuō)了這么多,也許有人會(huì)說(shuō), NO,你這兩個(gè)比對(duì)的case不嚴(yán)謹(jǐn),你只模擬了訪問(wèn)共享的數(shù)據(jù),如果是真的可并行執(zhí)行的代碼用微內(nèi)核的方案豈不是要降低性能嗎?平白自廢武功,將并行改成串行!確實(shí)如此,但是 內(nèi)核本身就是共享的。 操作系統(tǒng)本身就是協(xié)調(diào)用戶進(jìn)程對(duì)底層共享資源訪問(wèn)的。

所以真并行需要程序員自己來(lái) 設(shè)計(jì)可并行的應(yīng)用程序。

內(nèi)核本身就是共享的。共享資源的多線程訪問(wèn)就應(yīng)該嚴(yán)格串行化,并發(fā)爭(zhēng)鎖是一種最無(wú)序的方式,而最有效的方式則是統(tǒng)一仲裁調(diào)度。

在我們?nèi)粘I钪?,我們顯然能看到和理解為什么排隊(duì)上車(chē)比擁擠著上車(chē)更加高效。在計(jì)算機(jī)系統(tǒng)領(lǐng)域,同樣的事情我們也見(jiàn)于交換式以太網(wǎng)和PCIe,相比CSMA/CD的共享式以太網(wǎng),交換機(jī)就是一個(gè)仲裁調(diào)度器,PCIe的消息hub也是扮演著同樣的角色。

其實(shí),即便是宏內(nèi)核,在訪問(wèn)共享資源時(shí),也并不是全都是并發(fā)爭(zhēng)鎖的方式,對(duì)于敏感度比較高的資源,比如時(shí)延要求很高的硬件資源,系統(tǒng)底層也是仲裁調(diào)度實(shí)現(xiàn)的,比如網(wǎng)卡上層發(fā)包的隊(duì)列調(diào)度程序,此外對(duì)于磁盤(pán)IO也有對(duì)應(yīng)的磁盤(pán)調(diào)度程序。

然而對(duì)于宏內(nèi)核,更加上層的邏輯資源,比如VFS文件對(duì)象,socket對(duì)象,各種隊(duì)列等等卻沒(méi)有采用仲裁調(diào)度的方式去訪問(wèn),當(dāng)它們由多個(gè)線程并發(fā)訪問(wèn)時(shí),采用了令人遺憾的并發(fā)爭(zhēng)鎖模式,這也是不得已而為之,因?yàn)闆](méi)有哪個(gè)實(shí)體可以完成仲裁,畢竟訪問(wèn)它們的上下文是隔離的。

  來(lái)個(gè)插敘。當(dāng)進(jìn)行Linux系統(tǒng)調(diào)優(yōu)時(shí),瞄準(zhǔn)這些方面相關(guān)的熱點(diǎn)基本就夠了。大量熱點(diǎn)問(wèn)題都是這種引起的,open/close同一個(gè)文件,進(jìn)程上下文和軟中斷同時(shí)操作同一個(gè)socket,收包時(shí)多個(gè)CPU上的軟中斷上下文將包排入同一個(gè)隊(duì)列,諸如此類。\如果你不準(zhǔn)備去調(diào)優(yōu)Linux,或許你已經(jīng)知道Linux內(nèi)核在SMP環(huán)境下的根本缺陷,調(diào)它作甚。多看看外面的世界,搞不好比你眼前唯一的那個(gè)要好。

當(dāng)我們?cè)u(píng)價(jià)傳統(tǒng)UNIX以及Linux這種操作系統(tǒng)內(nèi)核時(shí),應(yīng)該更多的去看它們?nèi)笔Я耸裁?,而不是一味的覺(jué)得它們就是對(duì)的?!灸阏J(rèn)為它是的,可能僅僅因?yàn)樗悄愕谝粋€(gè)見(jiàn)到并且唯一見(jiàn)過(guò)的】

如果非要說(shuō)下概念,那就有必要說(shuō)說(shuō) 現(xiàn)代操作系統(tǒng) 的虛擬機(jī)抽象。

對(duì)于我們經(jīng)常說(shuō)的 現(xiàn)代操作系統(tǒng) 而言,按照最初的馮諾伊曼結(jié)構(gòu),只有 “CPU和內(nèi)存” 在 多處理(包括所有的多進(jìn)程,多線程等機(jī)制) 機(jī)制中被抽象了出來(lái),而對(duì)于文件系統(tǒng),網(wǎng)絡(luò)協(xié)議棧等等卻沒(méi)有進(jìn)行多處理抽象。換句話說(shuō),現(xiàn)代操作系統(tǒng)為進(jìn)程提供了 獨(dú)占的虛擬機(jī)抽象 ,該虛擬機(jī)僅僅包括CPU和內(nèi)存:

  •  時(shí)間片調(diào)度讓進(jìn)程認(rèn)為自己獨(dú)占了CPU。

  •  虛擬內(nèi)存讓進(jìn)程認(rèn)為自己獨(dú)享了內(nèi)存。

  •  再無(wú)其它虛擬機(jī)抽象。

在進(jìn)程使用這些抽象資源時(shí),現(xiàn)代操作系統(tǒng)無(wú)疑采用了仲裁調(diào)度機(jī)制:

  •  操作系統(tǒng)提供任務(wù)調(diào)度器仲裁CPU的分時(shí)復(fù)用(典型的是多級(jí)反饋優(yōu)先級(jí)隊(duì)列算法),為進(jìn)程/線程統(tǒng)一分配物理CPU的時(shí)間片資源。

  •  操作系統(tǒng)提供內(nèi)存分配算法仲裁物理內(nèi)存空間的分配(典型的是伙伴系統(tǒng)算法),為進(jìn)程/線程統(tǒng)一分配物理內(nèi)存映射給虛擬內(nèi)存。

顯然,正如本文開(kāi)頭說(shuō)過(guò)的,操作系統(tǒng)并未任由進(jìn)程們?nèi)ゲl(fā)爭(zhēng)搶CPU和內(nèi)存資源,然而對(duì)于其它幾乎所有資源,操作系統(tǒng)并未做任何嚴(yán)格的規(guī)定。操作系統(tǒng)以兩種態(tài)度對(duì)待它們:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2.  認(rèn)為其它資源并非操作系統(tǒng)核心的一部分,于是微內(nèi)核,用戶態(tài)驅(qū)動(dòng)等等就形成了概念。

  3.  認(rèn)為其它底層的資源也是操作系統(tǒng)核心的一部分,這就是宏內(nèi)核比如Linux的態(tài)度。

態(tài)度如何,這并不重要,宏內(nèi)核,微內(nèi)核,用戶態(tài),內(nèi)核態(tài),這些也只是概念而已,沒(méi)有什么大不了的。關(guān)鍵的問(wèn)題乃是:

  •  如何協(xié)調(diào)共享資源的分配。 或空間資源,或時(shí)間資源的或并發(fā)爭(zhēng)鎖,或仲裁調(diào)度的方式分配。

無(wú)疑,最大的爭(zhēng)議就在CPU/內(nèi)存之外如何協(xié)調(diào)非進(jìn)程虛擬化的文件系統(tǒng)的訪問(wèn)和網(wǎng)絡(luò)協(xié)議棧的訪問(wèn)。但無(wú)論它們倆的哪一個(gè),目前無(wú)論是宏內(nèi)核還是微內(nèi)核都有非常非常棒的方案。遺憾的是,這些很棒的方案都不是Linux內(nèi)核所采用的方案。

哦,對(duì)了Nginx便采取了類似微內(nèi)核,交換機(jī),PCIe的方法,Apache卻不是。還有很多別的例子,不再一一贅述,只是想說(shuō)一點(diǎn),操作系統(tǒng)領(lǐng)域,核心的東西都是大象無(wú)形的,而不是那些形形色色的概念。

摘錄一段王垠聊微內(nèi)核時(shí)的一段話:

跟有些人聊操作系統(tǒng)是件鬧心的事,因?yàn)槲彝鶗?huì)拋棄一些術(shù)語(yǔ)和概念,從零開(kāi)始討論。我試圖從“計(jì)算本質(zhì)”的出發(fā)點(diǎn)來(lái)理解這類事物,理解它們的起因,發(fā)展,現(xiàn)狀和可能的改進(jìn)。我所關(guān)心的往往是“這個(gè)事物應(yīng)該是什么樣子”,“它還可以是什么(也許更好的)樣子”,而不只是“它現(xiàn)在是什么樣子”。不明白我的這一特性,又自恃懂點(diǎn)東西的人,往往會(huì)誤以為我連基本的術(shù)語(yǔ)都不明白。于是天就這樣被他們聊死了。

這其實(shí)也是我想說(shuō)的。

so,忘掉微內(nèi)核,宏內(nèi)核,忘掉內(nèi)核態(tài),用戶態(tài),忘掉實(shí)模式,保護(hù)模式,這樣你會(huì)更深刻地理解如何仲裁共享資源的訪問(wèn)的本質(zhì)。

關(guān)于Linux在多核可擴(kuò)展性設(shè)計(jì)上的有哪些不足就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI