關於Web開發裡並發、同步、非同步以及事件驅動編程的相關技術

來源:互聯網
上載者:User

標籤:style   os   io   使用   java   strong   資料   問題   代碼   

一、開篇語

  我的上篇文章《關於如何提供Web服務端並發效率的非同步編程技術》又成為了部落格園裡“編輯精選”的文章,這是對我寫部落格很大的鼓勵,也許是被推薦的原因很多童鞋在這篇文章裡發表了評論,有童鞋說我這篇文章理論化很嚴重,沒有實際代碼和具體項目做支撐,這個評論讓我有種理論和實踐脫節的味道,所以我想在這裡談談我為什麼要寫這篇文章的原因,這篇文章是把我前不久學習多線程編程的一個總結。

  當我從我書堆裡找到所有與多線程開發相關的書籍簡單閱讀後,我發現了一個問題,在java裡開發多線程最強有力的實踐就是做服務端的並發處理,其他的應用都是小兒科,而這個實踐對於每個web程式員而言都是極具經濟價值的,所以我就想延著這個實踐繼續學習多線程,接著我發現並發處理這塊都離不開IO處理,同時IO處理的優劣直接關係著並發處理的效率問題,    關於並發的知識,有人說最好是寫寫代碼,告訴我們API如何運用,說實話簡簡單單寫幾行不是太難的事情,寫幾行代碼並不代表你能掌握它,掌握多線程絕不是集中精力看懂幾行代碼,看懂後頓悟的來一下:哦,明白了。

  要真的掌握某種技術你就必須要知其所以然,但是要理清並發的所以然就不那麼容易了,這其實是一種設計的思想,而不是簡單幾行代碼,幾個jdk提供的api,代碼和api只不過是實踐這些思想的實現,我之前學習線程開發,學習io的api,這個過程很早就開始,但這個過程都基本都是記住遺忘再記住再遺忘的死迴圈,究其原因就是因為它們本身的設計思想太深奧,你沒有理解這個設計思想,你就無法將那些api的內在關係串聯起來,所以最終的結果只會是遺忘。技術的本質就是工具,要用好工具的前提就是要真正理解這個工具的價值,這就好比斧頭設計出來時用來砍柴的,菜刀設計出來是為了切菜,如果我們用斧頭用來切菜,菜刀用來砍柴,這肯定要鬧笑話了,對於像線程和IO這樣複雜的工具,使用起來和使用像這種簡單工具菜刀和斧頭一樣,應該是物盡其才,各司其職,複雜工具的麻煩就是理解起來比較困難些了,自己得多花點時間和功夫了。

  我早期的文章都會寫好多代碼,但是最近的文章我會寫更多文字,我希望對我熟悉的技術有更進一步的理解,因此理論和猜想會更多點。

  本篇文章的標題是《關於Web開發裡並發、同步、非同步以及事件驅動編程的相關技術》,本文的目的就是要和大家一起好好的理解下標題裡很常見的概念,通過理解它們,指導我們今後對這些概念的學習和運用。

二、我們來好好理解下並發、同步和非同步這三個概念

  標題的三個概念在web開發領域太常見了,就算是入門web開發的童鞋隨便找本web開發的書籍都能找到這三個概念,但是如果你對這三個概念理解不夠透徹,如果在實際開發中正好碰到三個概念的交織在一起的問題,估計很多人就會麻了頭。

  並發

  首先是並發這個概念,我們看看現實中並發的例子。

  第一個例子:

  有一天你在家裡做飯,你這天的心情非常好,想大吃一頓,所以要有菜有湯還有酒喝,開始幹了,你首先會在電飯煲裡把飯煮好,飯在煮的時候,你會抽空去超市買瓶啤酒,買好了啤酒回到家裡你就要做菜了,你想做個湯,為了節約時間,你會先燒開水,燒開水同時,你會切菜,切好的菜就得炒菜,後面的過程此處省略一萬字了,地球人我想都明白以後是咋樣了,我就不再詳細講述了。 

  上面的描述裡煮飯、燒水、買啤酒、切菜、炒菜,它們都可以當作獨立的任務,這些任務都是為了達到某種特定的目的,它們之間是不能相互替代替換的,但是在實際操作裡你並不是等待某個任務做完了再去做另一個任務,而是會運用統籌方法,交叉進行,這麼做的好處就是效率很高,節約時間,這和程式員平時工作類似,一邊編寫程式,一邊聽歌,一邊和朋友同事在QQ裡聊天。

  第二個例子:

  現實生活裡還有一種並發,例如我們在食堂裡吃飯,去食堂吃飯的人很多,因此食堂開啟了好幾個打飯的視窗,如果打飯的視窗開的越多,那麼吃飯人打到飯所用時間也就最少,如果每個食客都有一個視窗一對一的服務,那麼食客基本就不用浪費任何時間去等待了,這種vip感在中國這麼資源緊張的國家裡,簡直太爽了,食堂打飯的並發就和我上篇文章裡講到的web服務端並發類似。

  這裡有列舉了兩個並發的執行個體,似乎有點多此一舉之嫌,但是如果我們仔細研究下這兩個例子,它們其實有本質的不同,第一個例子其實是一個人的並發,第二個例子就是多人的並發,用電腦的概念描述就是前一個例子就是一個線程完成的並發,後一個例子就是多線程完成的並發,第一個例子的線程載體就是做飯的人,第二個線程的載體就是每個打飯視窗的工作人員,這兩個例子其實就可以類比到我上篇文章提到的做法二和做法三,特別是第一個例子,雖然這個情境人們非常熟悉,但是到了程式開發裡卻有很多人把第一個執行個體並發給遺忘掉,特別是做web開發的人,並發就是多線程,一個線程怎麼可能做並發了,但是例子一說明一個線程是可以做並發的。

  由上面的描述,下面我要給出我自己總結的並發定義:

 並發就是讓一系列獨立的任務同時執行,同時執行包含兩種情形,一種就是完全獨立執行,例如在擁有雙核處理器的電腦裡,每個CPU在同一個時間裡處理不同的任務,另一種情形是一個任務還沒執行完,而CPU計算被閑置的時候CPU用來處理別的任務。

  而現實裡我們要做到高效的並發就得把兩種模式的並發混合起來使用,食堂打飯就是混合了兩種模式的並發,對於電腦兩種混合的並發才能把電腦的計算能力深度挖掘,所以做法三就是混合了兩種並發,做法三是高效和先進的,做法三是值得推廣的。

  接下來就要談談同步和非同步兩個概念了,記得剛工作不久,有次參加面試,面試官問我什麼是同步什麼是非同步,我當時的回答是:同步就是單線程,非同步就是多線程,當時那位面試官停頓了下,跟我說這個解釋沒有問題,但是在實際開發裡這個答案不能讓你把同步和非同步用的很好。現在回憶那位面試官給我答案的評定還是有道理的,下面我開始講同步和非同步了。

  同步:

  在電腦領域同步應該是指相互獨立的任務一個接著一個運行,拿上面做飯的例子描述就是煮飯煮好了才能去超市買啤酒,酒買好了才能切菜,菜切好了才能炒菜,菜炒好了才能燒水燒湯,明顯同步的方式在現實生活裡效率是很低的,不過同步有個很大的好處就是簡單,簡單的理論基礎就是一次就做一件事情,做的時候一心一意專心致志。

  非同步:

  下面就是非同步概念,同步和非同步在當代的電腦領域裡是兩個對等的概念,但是如果我們要追溯非同步本質,就會發現同步和非同步其實是一個因果關係,同步是因,非同步是果,換個說法同步就是非同步這個孩子他娘,所以我們要正確理解非同步就要明白同步做不好的事情,在web前端有個鮮活的例子可以說明這個問題,這個例子就是ajax,在ajax出現前,瀏覽器的一個獨立頁面和服務端的互動是通過一個socket進行的,這個socket相當於一個線程,它是採用同步處理的方式,所以沒有ajax的時代,單獨頁面每次和服務端的互動都只能做一件事情,而網路處理的速度往往是最慢,而且網路的效率很容易受到外界影響,因此同步請求會導致使用者使用頁面的體驗很不好,同步網站時刻都在考驗著使用者的耐心,這就導致ajax的出現,ajax本質就是瀏覽器提供了一個新的socket連結,這個socket是有別於同步的socket,它可以獨立於同步socket運行,有了ajax這個socket我們就可以在不影響頁面同步操作的前提下也能從服務端擷取資料,這就好比瀏覽器由原來一個人完成和服務端的互動變成了現在兩個人完成和服務端的互動操作,它們各司其職,共同完成頁面上的功能。

  非同步和並發的關係和區別:

  非同步作業和並發看起來很像,特別是和我前面講到並發的做飯執行個體很像,的確並發和非同步常常是交織在一起的,但是它們還是有很大的區別,這個區別在於它們所達到的業務目的,並發是業務含義是能做更多事情,而非同步是讓多個人共同完成一個任務,非同步其實是通過專業角度把一個大任務拆分成相對獨立小任務,讓更加專業的人完成這個小任務,小任務完成後最後匯總成一個大任務的結果,上面ajax就是這樣的道理,其實我以前著重研究的hadoop就是一個典型的非同步任務系統。

  非同步和並發共同點都是通過多線程來實現,通過它們在業務情境的區別,我們反過來學習多線程,就知道多線程能為我們做好哪些事情,那麼當你碰到需要使用多線程的業務情境就知道按什麼思路來分析這個業務情境了。

三、關於事件驅動編程

  在我上篇文章裡我反覆寫了好多事件驅動這四個字,到了本文裡事件驅動後面我加了兩個字編程,為什麼加它我後面會講到。

  全世界最熟悉事件驅動的程式員是哪種程式員?答案是前端工程師,不管是案頭前端還是web前端都是世界上最熟悉事件驅動的,以web前端為例,我們做頁面可以不去想什麼物件導向編程,什麼jQuery架構咋用,但是為按鈕,為頁面元素添加相關事件操作肯定是不可缺少的,而web前端的事件處理機制就是標準的事件驅動機制,為了講清楚事件驅動,這裡我回顧下頁面裡事件機制,我們開發頁面的事件時候,第一步就是定義事件(定義事件就是在定義一個函數)或者說為事件定義一個動作,並把事件綁定到指定的元素上,如果我們沒有觸發元素上的事件,那麼定義好的函數也就不會執行,如果元素上的事件被觸發了,定義好的函數才會執行。代碼不提供了,這個太簡單和平常了。

  關於瀏覽器裡事件機制實現方案,我找了許久都沒有找到完整的資料,因此這裡我大膽揣測下事件機制的實現方案,下面的內容完全是我的猜想,不一定和實際相符,具體如下:

  首先我要說多線開發程裡有一個經典的設計方法,這個方法就是生產-消費者模型,生產-消費模型特點就是生產者和消費者被一個中間隊列分隔開來,不管是生產請求還是消費結果都是通過這個中間隊列中轉,這樣就可以把生產者和消費者關係解耦,事件實現機制從宏觀上和生產-消費模式類似,這個類似不是指設計思想,而是溝通雙方聯絡的那個中介層。

  事件處理的機制裡應該有個事件處理器,事件處理器位於元素和事件處理方法的中間位置,我們在定義事件的時候就是等於在事件處理器裡定義元素和事件處理方法的關係,當這種對應關係定義好後,事件處理器就會啟動一個死迴圈,這個迴圈反覆檢測元素的狀態變化,當事件處理器發現某個狀態產生了變化,處理器就會找到對應的事件處理方法,然後執行這個方法。

  Nodejs是一個事件驅動的語言,這是官方對nodejs的定義,很多評論說nodejs是第一個把事件驅動上升到語言層級的程式設計語言。所以本文我在事件驅動後面加上了編程兩字。

傳統語言做開發都是按時間先後順序進行的,這麼做既可以降低語言的學習成本,也讓開發代碼思路比較容易控制,但是現實情境是複雜的,這種按事件順序的開發流程並不一定是我們解決現實問題的最佳方式。這好比我們做一件事情,在做的時候我們會碰到很多情況,由於發生的情況的不同,那麼這件事情的結果可能就會因為情況不同而發生變化,如果按照時間順序的編程方式想做好上面的事情會讓程式變得十分複雜,因為我們要按照時間順序做出各種不同執行路徑,這就是排列組合的辦法了,這顯然讓事情變得複雜了,如果用事件驅動編程方式,我們只要定義好事務的起因,各種不同的過程情況,以及所能得到結果,換句話說我們首先只要關注實體內容而忽略事務關係問題,而事務關係則是在事件處理器裡定義的,當我們發送給事件處理器一個指示訊號,處理器就會對應找到某個行為,那麼事件驅動編程就簡化了程式開發的流程。

  事件驅動編程實現的核心技術就是能讓方法變成對象能在事件處理的流程裡傳遞,方法得到事件管理器的指令後在合適的位置上被促發,這就是回呼函數,而javascript語言裡函數可以當做對象傳遞,也就保證了事件驅動編程上升到語言層級變成了可能,我想這就是nodejs作者使用google的V8引擎設計出nodejs的重要原因之一。

  回呼函數改變了傳統程式開發的流程,但是大量使用回呼函數的代碼常常會變得晦澀難懂,這也是javascript語言很掌握的重要原因之一。鑒於回呼函數這個毛病出現了promise編程,promise的目的是讓回調編程看起來像按時間順序編程的方式,我前端時間研究了下promise,但是沒有深究,原因是回調本來就很難理解,回調變成順序編程,那豈不是更加糊裡糊塗,按現在技術特點,我會選擇慎用promise技術。

四、小結

  本文的主要內容就到此為止,鑒於上篇文章有些內容有很大的爭議,本文想做一定的解釋說明:上文最大的問題還是IO的解釋上,我承認自己對IO其實理解不太深入,所以我只是用文字描述非阻塞IO的處理,這段文字寫的時候我還是很注意的,盡量不講太多,我當時只用一個理念來寫這個實現,就是非阻塞IO的具體實現裡一定會有一個和事件處理器相類似的中介層來協調IO操作和CPU的操作,這點我自信不會有錯。其實IO技術在java裡相當複雜的,比較難學,現在jdk提供的IO的模型有三大類,BIO(阻塞IO),NIO(阻塞IO或者叫新IO)以及AIO(非同步IO或者叫NIO2.0),jdk的io是建立在作業系統IO上的,所以學習IO真的要多花點心思和精力,這是我今後學習研究的一個重點。

  此外,在電腦裡不管執行什麼任務都會包含IO操作和CPU計算兩個過程,IO的速度問題常常拖累了CPU的計算,由於某些IO太慢了,如果站在CPU的角度,它等待IO處理的代價實在太高了,所以先進的IO就是為了調整IO處理和CPU計算的關係,我覺得新IO解決方案要解決的核心問題。

  好了,本文寫到這裡,本文和上文類似都是談自己對某些技術的理解,文字很多,幾乎沒啥代碼,希望童鞋們多拍拍磚,有問題才能進步的更快。

 

 

關於Web開發裡並發、同步、非同步以及事件驅動編程的相關技術

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.