為AJAX實現互斥

來源:互聯網
上載者:User

隨著AJAX範例得到越來越廣泛的應用,瀏覽器頁面可以在向後台伺服器請求資料的同時保持前端使用者介面的活躍性(因此在AJAX中稱為非同步)。然而,當這兩個活動同時訪問共用的JavaScript和DOM資料結構時就會引發問題。JavaScript沒有提供針對該並發程式問題的經典解決方案。本文描述了作者在互斥機制方面的新見解,該經過驗證的互斥機制在JavaScript中能發揮良好的作用。

為什麼需要互斥?

當多個程式邏輯線程同時訪問相同資料的時候,問題便產生了。程式通常假定與其互動的資料在互動過程中不發生改變。訪問這些共用資料結構的代碼稱為臨界區,一次只允許一個程式訪問的機制被稱為互斥。在AJAX應用程式中,當對來自XMLHttpRequest的應答進行非同步處理的代碼同時操縱正在被使用者介面使用的資料時,便會發生這種情況。這個共用的資料可能是用於實現MVC資料模型的JavaScript和/或web頁面自身的DOM。如果二者中的任一個對共用資料做了不協調的更改,那麼二者的邏輯都將中斷。

也許您會說“等等,為什麼我沒有遇到過這種問題?”。遺憾的是,這種問題是同步依賴的(也叫做競態條件),因此它們並不總是發生,或者也許從不發生。它們的或然性基於許多因素。基於健壯性考慮,富internet應用程式應該通過確保這些問題不會發生來阻止出現這種情況。

因此,需要一種互斥機制來確保同時只能開啟一個臨界區,並且在它結束之後才能開啟另一個。在大多數主StreamCompute機語言和執行架構中,都提供互斥機制(經常是幾種),但是應用於瀏覽器端的JavaScript卻沒有提供這種互斥機制。雖然存在一些無需專門的語言或環境支援的經典互斥實現演算法,但是即使這樣還是需要一些JavaScript和瀏覽器(如Internet Explorer)所缺少的要素。接下來介紹的經典演算法在這些瀏覽器和語言中能發揮良好的作用。

麵包店演算法

在電腦科學文獻中的幾種互斥演算法中,所謂的Lamport麵包店演算法可以有效地用於多個相互競爭的控制線程,該演算法中線程之間的通訊只能在共用記憶體中進行(即,不需要諸如訊號量、原子性的set-and-test之類的專門機制)。該演算法的基本思想源於麵包店,因為麵包店需要先取號然後等候叫號。清單1給出了該演算法的架構(引自Wikipedia),該演算法可以使各線程進出臨界區而不產生衝突。

清單1. Lamport麵包店演算法虛擬碼

// declaration & initial values of global variables
Enter, Number: array [1..N] of integer = {0};
// logic used by each thread...
// where "(a, b) < (c, d)"
// means "(a < c) or ((a == c) and (b < d))"
Thread(i) {
 while (true) {
  Enter [i] = 1;
  Number[i] = 1 + max(Number[1],...,Number[N]);
  Enter [i] = 0;
  for (j=1; j<=N; ++j) {
   while (Enter[j] != 0) {
    // wait until thread j receives its number
   }
   while ((Number[j]!=0)
     && ((Number[j],j) < (Number[i],i))) {
    // wait until threads with smaller numbers
    // or with the same number, but with higher
    // priority, finish their work
   }
  }
  // critical section...
  Number[i] = 0;
  // non-critical section...
 }
}

如上所示,該演算法假定各線程清楚自己的線程編號(常量i)和當前正在活動的線程總數(常量N)。此外,還假定存在一種等待或休眠方式,例如:暫時將CPU釋放給其他線程。遺憾的是,Internet Explorer中的JavaScript沒有這種能力。雖然如此,如果實際運行在同一線程上的多個代碼部分表現為各自運行在獨立的虛擬線程上,那麼該麵包店演算法不會中斷。同樣,JavaScript具有一種在指定延遲後調度函數的機制,所以,可以使用下面的這些方法來最佳化麵包店演算法。

Wallace變體

在JavaScript中實現Lamport麵包店演算法的主要障礙在於缺少線程API。無法確定當前正在哪個線程上運行以及當前正在活動的線程數目,也無法將CPU釋放給其他的線程,無法建立新的線程來管理其他線程。因此,無法查證如何將特定的瀏覽器事件(例如:單擊按紐、可用的XML應答等)分配到線程。

克服這些障礙的一種方法是使用Command設計模式。通過將所有應該進入臨界區的邏輯以及所有啟動該邏輯所需的資料一起放入到command 對象中,可以在負責管理command的類中重寫麵包店演算法。該互斥類僅在沒有其他臨界區(封裝為獨立的command對象方法)在執行時調用臨界區,就像它們各自運行在不同的虛擬線程中一樣。JavaScript的setTimeout()機制用於將CPU釋放給其他正在等待的command。

為command對象假定一個簡單的基類(見清單2中的Command),可以定義一個類(見清單3中的Mutex)來實現麵包店演算法的Wallace變體。注意,雖然可以通過很多方式在JavaScript中實現基類對象(為了簡潔起見,這裡使用一種簡單的方式),但是只要各個command對象擁有某個惟一的id,而且整個臨界區被封裝在單獨的方法中,那麼任何對象模式都可以使用這種方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.