賴勇浩(http://laiyonghao.com)
javascript
線程是指進程中的一個單一順序的控制流,是操做系統可以調度的最小單位,一個進程中能夠有多條線程,分別執行不一樣的任務。線程有內核線程和用戶線程之分,但在本文中僅指內核線程。在軟件開發中,使用線程有如下好處:
一、在多核或多路 CPU 的機器上多線程程序可以併發執行,提升運算速度;
二、把 I/O,人機交互等與密集運算部分分離,提高 I/O 吞吐量和增進用戶體驗。
線程的缺點也很明顯:
一、建立一條線程須要較大的內存開銷,致使不能建立海量的線程;
二、線程由操做系統調度(分配時間片),線程切換的 CPU 成本比較高,致使大量線程存在時大量 CPU 資源消耗在線程切換上;
三、同一進程的多條線程共享所有系統資源,在多線程間共享資源須要進入加鎖,大量的鎖開銷不提,重要的是加大了編寫程序的複雜性,這一點你看看有多少書名含有「多線程」三個字就明白寫個多線程應用有多難了;
四、 I/O 方面,多線程幫助有限,以 TCP Socket Server 爲例,若是每個 client connection 由一條專屬的線程服務,那麼這個 server 可能併發量很難超過 1000。爲了進一步解決併發帶來的問題,現代服務器都使用 event-driven i/o 了。
event-driven i/o 解決了併發量的問題,但引入了「代碼被回調函數分割得零零碎碎」的問題。特別是當 event-driven i/o 跟 multi-threading 結合在一塊兒的時候,麻煩就倍增了。解決這個問題的辦法就使用綠色線程,綠色線程能夠在同一個進程中成千上萬地存在,從而能夠在異步 I/O 上封裝出同步的 APIs,典型的就是用基於 greenlet + libevent 開發的 python 庫 gevent。綠色線程的缺陷在於操做系統不知道它的存在,須要用戶進行調度,也就沒法利用到多核或多路 CPU 了。爲了解決這個問題,不少大牛都作出了巨大的努力,而且成果斐然,scala、google go 和 rust 都較好地解決了問題,下文以 rust 的併發模型爲例講一下。
rust 提出一個 Task 的概念,Task 有一個入口函數,也有本身的棧,並擁有進程堆內存的一部分,爲方便理解,你能夠把它看做一條綠色線程。rust 進程能夠建立成千上萬個 Tasks,它們由內建的調度器進行調度,由於 Tasks 之間並不共享數據,只經過 channels/ports 通訊,因此它們是可並行程度很高。rust 程序啓動時會生成若干條(數量由 CPU 核數決定或運行時指定)線程,這些線程並行執行 Tasks,從而利用多個 CPU 核心。
如 上圖,rust 應用程序不停地 spawn 出一個又一個 Tasks,它們由 tasks 調度器管理,在適當的時機,調度器會把某一個 Task 分配給原生線程執行,若是這個 Task 進入 I/O 等待或主動讓出 CPU(sleep),那麼這個 Task 會被交回給調度器,而相應的原生線程會執行另外一個新分派的 Task。儘管使用 rust 編程語言是不能建立線程的(直接調用 C 函數不算),但 rust 應用程序其實是多線程的(通常狀況下),它可以充分地利用多核或多路 CPU。
綜上,相似 rust 的 Task 的概念是比線程更好的併發模型,更安全,編寫的代碼也更加容易維護(關於維護性,我相信寫過 gevent 程度或 go 程序的同窗會認同的)。線程固然不會消亡,但隨着 scala/go/rust 的成熟,在能夠預見的未來,線程會退到它呆着的角落:遠離普通程序員,只有少數人須要瞭解它的細節。php
賴勇浩(http://laiyonghao.com)css
C++C++ 在 2011 年其實風頭甚勁,C++2011 標準出臺,gcc/msvc/clang 都很快速地支持了許多新特性,新興的移動設備的性能較差,更是 C++ 的新舞臺,在這個時候唱衰 C++,壓力很大。我使用 C++ 年頭很多,但除了在校的時候寫過兩個小遊戲參加過兩個比賽(分別是面向社會和麪向大學生的)弄些證書好找工做之外,在工做中只用過大概不到一年半,作《斬 魂》(http://zh.163.com)的早期版本,寫了服務器端的幾條進程和客戶端的 GameAI 部分。經驗少,並且寫得很差,因此基本上有人在 weibo 上問我 C++ 的問題,我都是轉發給 @bnu_chenshuo 和 @miloyip 等真正的行家去回答的。因此實際上今天寫這一篇,我底氣非常不足,可是朋友們給前兩篇很大面子,弄得我騎虎難下,只好硬着頭皮寫了。
前 文提到 C++ 的新標準,頗有必要提一下標準化對 C++ 的影響。首先咱們要確定標準定製對 C++ 的積極做用,但標準化過程當中的超長流程,一次次將 C++ 推向深淵。C++ 的第一個標準是 1998 年的 ISO/IEC 14882:1998,距離整個 90 年代最流行的 C++ 程序庫 MFC(Microsoft Foundation Class Library)的第一個版本發行時間已經整整 6 年。1998 年,MFC 版本號爲 6.0,與其一塊兒發佈的 Visual C++ 6.0 佔有了巨大的市場。由於 MFC 發佈得標準制定的時間早,因此 MFC 內部實現了許多後來標準庫裏也有的組件,好比各類數據結構容器。VC6 的市場佔有率讓 windows 平臺下開發的許多 C++ 程序員甚至不知道有 STL,同時也無視 C++98 標準,從更兼容標準的 VC2002/2003 的市場佔有率就能夠看出來,直到今天,我知道國內很多公司仍是隻用 VC6 的。
其實在 90 年代,計算機的運算能力有限,市場上很是須要一款性能較高、抽象較強的編程語言,C++ 得到了成功,但它標準化的時間過長,形成各類編譯器有各自互不兼容的「方言」,成了它的第一個軟肋。第一個瞄準這個軟肋的就是 java,java 在 1995 年推出,雖然性能稍遜,但它有更高的抽象能力、也更安全,而且更容易跨平臺,因此迅速得到了成功;第二個瞄準這個軟肋的是 C#,微軟不能推進 C++ 發展,又不肯 C++ 的市場被 java 鯨吞,因而在 2001 年推出了 C#,通過 10 年的發展和微軟大量的金錢推廣,C# 已經成功得到了它應有的江湖地位。
雖然 java/c# 都不是善類,但 C++ 在 21 世紀的第一個十年裏仍然地位穩固,這是由於 Linux 和 MacOS X 大獲成功,在這兩個平臺上 C++ 都是很是有競爭力的編程語言,C++ 天然水漲船高。但隨着 web2.0 和 web app 概念的興起,以及 CPU 的主頻進一步提高,服務器端編程語言漸漸地對執行效率再也不敏感,而是更在乎程序員的開發效率,衆多的腳本語言開始蠶食 C++ 的市場份額,從早期的 perl 到後期的 python/php/ruby,在 2005 年之後,C++/java/C# 等靜態類型的編譯型語言的市場份額都降低了,新興的貴族是動態語言。面對動態語言在開發效率上的強勁挑戰,C++ 社區除了在 2003 年對 C++98 作了小小的 patch,基本上睡着了,徹底沒有應對之策,哦不,連應用的姿態都沒有。
進入 21 世紀的第二個十年,市場又發生了變化,雲計算越走越近,也許咱們中的大部分人今天還能夠說只聞其聲不見其形,但 The Data Center Is the Computer 這句話你們應該以爲很務實:完成一個用戶操做,在服務器端的進程間通訊次數史無前例地多。在這個十年,咱們須要這樣的編程語言:
一、能充分利用現代 CPU 的計算能力,不只僅是多個核心,更是巨大的 L1/L2/L3 Cache、超線程等;
二、可以大量減少異步 I/O 的性能提高的同時帶來的反作用:異步編程的複雜性以及對可維護性的傷害;
兩 句話其實也能夠壓縮爲一句:須要有更好的併發模型的語言。一開始你們都在已有的編程語言中尋找,而後找到了 erlang,實踐證實 erlang 自有其侷限,因此 google go/scala/rust 等新語言如同雨後春筍般撥地而出。C++2011 標準努力下降 C++ 的編程難度,並提供了線程庫以支持現代 CPU,若是在 2005 年,這個標準絕對有競爭力,但在今天,它只能成爲新的編程語言的墊腳石。正如 IE 最大的用處是用來下載其它瀏覽器,不久以後,也許會流行新的冷笑話:C++ 最大的用處就是用來實現其它編程語言。
市場一直在尋找一門中間的高級 語言,它上承 C 語言和彙編語言,下啓腳本語言。C++ 最早搶佔了高地,並在與 java/c# 的爭鬥中不落下風,但新的十年,它的對手又增長了 google go/scala/rust 等新銳,而且新的標準不可能在兩三年內再次出臺,兩三年內新銳成長起來後,留給它的位置就很少了。
上 文討論的基本上都是服務器編程,有必要再來看一下桌面和移動設備領域。首先看桌面軟件,rust 是 mozilla 基金會開發系統程序語言的,它的定位是部分取代 C++ 開發 firefox 的瀏覽器,因此 rust 會進入桌面開發,google go 確定會順道啃一口。移動設備方面,主要是 android、ios 和 windows phone,隨着移動設備性能加強,編譯型語言加腳本的模式就會佔大頭,編譯型語言方面主要是 C++ 和 Objective-C 在競爭,C++ 會佔上風(但需求量遠遠小於腳本,從 lua 在 2011 年的增加速度能夠印證),可是誰知道 rust 之類的會不會進入移動設備呢,畢竟移動設備的 CPU 核心也愈來愈多了呀,C++ 仍是前景堪憂。
回首 C++ 的 30 年,展望它的將來,總結起來可能就是:標準化流程拖死人了。若是不是 15 年不能標準化,java/c# 的攪局可能不會出現;若是在 2005 年可以應對動態語言……若是雲時代有更好的併發模型……
題 外話:java/c# 不會有 C++ 的問題,由於它們有本身的平臺,有巨大的財富支撐。特別是平臺的做用很是巨大,你能夠想像一下若是 Adobe 有本身的瀏覽器或手機操做系統 ActionScript/MXML 會不會是今天的境地;也能夠想像一下 google go 的飛速發展動力是什麼。
html