相同執行緒是一個並發模型,這種並發模型的意義是一個單執行緒的系統向外擴展成為N個單執行緒的系統。這個結果就是N個單執行緒的系統並行運行。
一個相同執行緒的系統不是一個純粹的單執行緒系統,因為它包含了多個執行緒。但是這些線程中的每一個就像是單線程系統運行一樣。
為什麼是單執行緒的系統
你可能想知道為什麼每一個都設計成單一執行緒系統呢。單線程系統已經普及,因為他們的並發模型比多線程更簡單。單線程系統不會跟其他線程共享任何資料。這個就使得執行緒去使用非並發的資料結構,以及更好的利用CPU和CPU快取。
不幸的是,單執行緒系統不會充分利用現代CPU。一個現代的CPU經常會有2,4或更多的核心。每一個核心的功能都可以作為一個單獨的CPU。一個單線程系統只是利用了這些核心中的一個,如下圖所示:
#相同的線程,單線程的擴展
為了充分利用所有CPU的內核,一個單線程的系統可以向外擴展去利用整個的計算機。
每一個CPU一個執行緒
相同的執行緒系統通常都是在電腦中每一個CPU執行一個執行緒。如果這個電腦包含4個CPU,或是有4個核心的CPU,然後它將標準的運行相同執行緒的4個實例(4個單執行緒系統),示意圖如下:
沒有共享的狀態
一個相同的執行緒系統看起來跟多執行緒系統相似,因為一個相同的執行緒是有多個執行緒在內部運行的。但是這裡有一個微妙的不同。
在相同的執行緒和一個多執行緒系統中的不同是在相同的執行緒的系統中沒有共享的資料。這裡沒有線程同時存取的記憶體。沒有並發的資料結構等等。不同如下圖所示:
共享狀態的減少是使得每個執行緒表現為它是否為單一執行緒的系統。然而,一個相同線程的系統可以包含不只是一個單線程,以至於它不是一個真正的「單線程系統」。缺乏一個更好的名字,我發現它更準確的去叫這樣一個系統為相同線程的系統,而不是一個“擁有一個單線程設計的多線程系統”。相同的線程說起來非常簡單,並且理解起來更簡單。
相同的執行緒主要的意味著資料運行在相同的執行緒裡面, 以及不會有共享資料。
負載分配
明顯的,一個相同執行緒的系統需要共享給這個工作負載在執行的單一執行緒實例之間。如果不是,只有一個實例將會得到任何工作,而這個系統將會實際上是單執行緒的。
怎麼在不同的實例確切的分配負載取決於你的系統的設計。我將會在下面的部分覆蓋一些。
單執行緒的微服務
如果你的系統包含了多個微服務,每個微服務都可以運行在單一執行緒模式下。當你部署多個單執行緒的微服務到相同的電腦上的時候,每一個微服務都可以在一個單獨的CPU上執行一個單獨的執行緒。
微服務不會共享任何數據,以至於微服務對於一個相同執行緒系統來說是一個好的使用案例。
有分片數據的服務
如果你的系統確實不需要共享數據,或者至少一個資料庫,你可能能夠去分片這個資料庫。分片意味著這個資料被分開到了多個資料庫中。這個資料是有代表性的分離的,以至於互相相關的資料位於相同的資料庫中。例如,屬於一些「owner」實體的所有資料將會插入到相同的資料庫中。分片脫離了這個教學的範圍,以至於你將會不得不查閱一些關於這個主題的一些教學。
線程通訊
#如果在相同執行緒中的執行緒需要通信,他們透過訊息傳遞做這個。一個線程想發送一個訊息給線程A,它可以透過產生一個訊息去做這個(一個位元組序列)。線程B然後可以拷貝和整個訊息(字節序列),並且讀取它。透過拷貝這個訊息,線程B確定當它修改這個訊息的時候,線程A是不能修改這個訊息的。一旦它被拷貝了,對於線程A它是不可變的。
此過程示意圖如下:
這個執行緒通訊可以通過佇列,管道,Unix套接字,TCP套接字取代。無論什麼適合你的系統。
更簡單的並發模型
每一個運行在它自己執行緒的系統如果它是單執行緒的可以使用相同的執行緒系統去實現。這就意味著相對有共享狀態的線程來說內部並發模型變得更加簡單了。你不需要擔心並發的資料結構以及所有的並發問題。
插圖
這裡有一個單線程,多線程,相同線程系統的插圖。你可以更簡單的得到他們之間不同的一個概述
第一個圖顯示了一個單線程的系統:
#