程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Parallet - My Dynamic Language - 一款異步編程語言

Parallet - My Dynamic Language - 一款異步編程語言

編輯:關於C語言

簡介:

      Parallet是筆者自創的一種新的編程語言. 當初的定位是DotNet下的異步腳本, 用來彌補C#對異步編程的不足.  (筆者想實現一些異步操作超多超復雜的服務器應用, 但是用C#做起來超難. )

     就在昨天, 筆者完成了初步的動態編譯到IL的實現. 讓大部分不需要異步執行的函數, 編譯成CLI的方法. 這些函數由解釋執行轉換為編譯執行後, 性能提高了100多倍. (解釋執行的性能和VBScript差不多)

    基本上, 現在很多架構上的設計, 都已經完成. 大方向比較明確, 剩下的, 都是無窮無盡的細節問題.


異步:

    在異步編程方面, 由於新語言的異步函數的特點, 讓它除了支持傳統的命令式編程, 還支持新的異步方式編程, 讓開發者可以用傳統的命令式語法去編寫異步操作, 一次過擺脫為了異步而異步的各種麻煩的編程手法.

    而且, 這個新的語法體系裡, 函數默認是異步的, 系統會自動分析哪些函數需要異步處理, 而哪些不需要. 所以, 這個語言並沒有為異步操作而創建任何一個關鍵字. 非常簡單容易接受.

    實際上一時之間要描述出這個新的異步語言, 是非常非常難. 這表現在多個方面:

        - 筆者的語文水平極差, 表達能力極差, 心裡所想的東西並不能很好地表達出來.

        - 和傳統編程一摸一樣的語法, 這是優點, 但也導致讀者會認為這根本就和異步編程沒什麼關系..

        - 如果讀者沒有做過異步編程的工作, 那麼就無法知道異步編程有多麻煩,
          不知道異步編程的麻煩之處, 也不會明白異步函數調用異步函數的好處.

    如果說代碼就是文檔的話, 那麼或許用代碼來解釋這個異步函數的概念, 可能是最好的. 以下就用例子來慢慢說明異步函數的概念與意義.


示例:

    以下示例, 力求簡單, 都是隨便手寫, 用JS語法, 目的是讓大家更容易理解.

    傳統,阻塞型,同步調用

function LoadConfig(){    var xhr=new XMLHttpRequest();    xhr.open("GET","config.aspx",false);    xhr.send("");    return ParseConfig(xhr.responseText);}    上面代碼, 通過給xhr.open傳遞一個false, 指定為sync模式. 當xhr.send("")執行時, 除非服務器返回或者出錯, 否則當前代碼就會被阻塞, 當前的線程也會被阻塞, 浏覽器也不會響應.

    在UI線程裡, 發生阻塞, 界面假死, 對用戶是非常不友好的事. 為了解決這個問題, xhr提供了異步模式

    傳統,回發型,異步調用:

function LoadConfig(){    var xhr=new XMLHttpRequest();    xhr.open("GET","config.aspx",true);    xhr.onreadystatechange=function()    {        if(xhr.readyState<4)return;        ParseConfig(xhr.responseText);    }    xhr.send("");}    通過給xhr.open傳遞一個true, 指定為async模式. xhr.send("")後, 就立刻返回, 不會發生阻塞, 但程序也不會立刻得到結果. xhr得到服務器的響應後, 執行onreadystatechange指定的方法, 來通知它本身的調用者去處理異步的結果.

    咋一看, 兩個LoadConfig用了不同的方式, 實現了相同的事了不 ?  沒有 !

      假如有人寫了這麼一段代碼 :

var config=LoadConfig();InitMySystem(config.OptionName);    阻塞方式的LoadConfig能阻塞線程, 等待服務器回復, 並且把結果返回給它的調用者.

    但是, 如果把LoadConfig裡的xhr改成異步調用, 那麼config=LoadConfig()就不能正確地給config傳遞服務器結果了.

    所以, 要解決這個問題, 方案是建立新的函數 LoadConfigAsync

function LoadConfigAsync(callback){    var xhr=new XMLHttpRequest();    xhr.open("GET","config.aspx",true);    xhr.onreadystatechange=function()    {        if(xhr.readyState<4)return;        callback(ParseConfig(xhr.responseText));    }    xhr.send("");}    而在外面的代碼, 也需要響應改變成

LoadConfigAsync(function(callback){    InitMySystem(config.OptionName);});    這種方式, 就是目前大多數編程語言的現狀. 無論是JS,還是win32下的異步socket,還是DotNet的BeginXxx/EndXxx, 都是通過傳遞回發函數(事件也是傳遞回發函數的形式).

    這種方式, 一旦函數之間的嵌套比較深入, 就會變得非常復雜, 而且它很難實現各種循環, 更難實現的, 就是如何處理異步錯誤. 很多時候, 代碼給拆分出非常多塊, 基本上每一小塊都要try/catch, 處理異常後要返回也是非常麻煩.

    所以, 傳統的異步編程, 非常不直觀, 非常麻煩. 這就是Parallet希望能解決的問題.

    在Parallet裡, 所有的函數, 默認都是異步函數. 開發者不需要考慮阻塞不阻塞的問題, 這是語言需要幫開發者解決的問題.

    上面的問題, 在Parallet是這樣寫的 :  (語法形式,XHR為虛構)

//PARALLET代碼function LoadConfig(){    var xhr=new XHR();    xhr.open("get","server.aspx");    xhr.send("");    return ParseConfig(xhr.responseText);}var config=LoadConfig();InitMySystem(config.OptionName);    在Parallet裡, xhr.open不再需要指定同步和異步. 因為默認就是異步.  但是, xhr.send("")之後, 服務器沒有返回, 調用鏈會被掛起, 不會阻塞當前線程. 當前線程會繼續跑去執行其他事情.  當server.aspx返回後, 當前線程又會跑回來, 繼續執行ParseConfig的部分, 然後把LoadConfig的結果返回給config變量, 繼續執行外面的代碼.

    可以看出, Parallet的主要思想, 就是釋放當前線程, 去干別的事, 然後再回來繼續執行代碼.

    這個看上去好像很簡單, 但是目前的主流語言都無法直接在CPU指令或IL的層次上實現它. 主要原因就是目前的計算機體系, 是用stack來儲存函數調用鏈上的各種參數返回值和臨時變量的. 如果要實現函數執行到一半就釋放線程, 那麼操作系統就必須要把stack上的數據全部儲存起來, 當需要恢復函數的執行時, 又需要把數據恢復到stack上, 然後讓線程繼續.

    而Parallet也一樣, 並沒有在IL上實現它, 所以Parallet執行異步函數時, 只能解釋執行, 所有的參數返回值臨時變量, 都是儲存在虛擬機的特殊stack上, 而不是線程的stack. 也就是說, 不存在這個保存和恢復數據的過程, 但性能的損失也是非常多. 基於這個解釋型的虛擬機, 任何函數都能隨時掛起, 線程可以隨時切換去做其他的事.

    也許大家還沒有看到實質的好處, 因為例子實在太簡單. 如果在外面套一層try/catch, 就能看得出異步函數的優越性了

//PARALLET代碼function LoadConfig(){    var xhr=new XHR();    xhr.open("get","server.aspx");    xhr.send("");    return ParseConfig(xhr.responseText);}try{    var config=LoadConfig();    InitMySystem(config.OptionName);}catch(x){    alert("initialize failed.");}    上述的代碼,無論在異步操作的任何環節出錯, 錯誤都能被統一catch住.  如果是換成傳統的LoadConfigAsync, 要讓多個被分割的函數裡統一處理錯誤? 非常難..非常難...(無限回音...) ,  這也是筆者用C#來編寫那個服務器應用時最惱火的事.

最後

    上面用代碼來說明了一下Parallet和傳統異步編程的區別. 可以看出,Parallet能把異步問題大大地簡化掉. 

    沒有新語法,沒有新關鍵字,一切都是那麼的簡單, 自然..

    在這個模式下, 有很容易的方式去處理各種異步,並發, 多線程的綜合問題.  這個筆者會陸續補充上.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved