小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Jetty 服務器的并發(fā)處理

 CevenCheng 2011-09-05
為了使用 Continuatins,Jetty 必須配置為使用它的 SelectChannelConnector 處理請求。這個 connector 構建在 java.nio API 之上,允許它維持每個連接開放而不用消耗一個線程。當使用 SelectChannelConnector 時,ContinuationSupport.getContinuation() 提供一個 SelectChannelConnector.RetryContinuation 實例(但是,您必須針對 Continuation 接口編程)。當在 RetryContinuation 上調用 suspend() 時,它拋出一個特殊的運行時異常 -- RetryRequest,該異常傳播到 servlet 外并且回溯到 filter 鏈,最后被 SelectChannelConnector 捕獲。但是不會發(fā)送一個異常響應給客戶端,而是將請求維持在未決 Continuations 隊列里,則 HTTP 連接保持開放。這樣,用來服務請求的線程返回給 ThreadPool,然后又可以用來服務其他請求。暫停的請求停留在未決 Continuations 隊列里直到指定的過期時間,或者在它的 Continuation 上調用 resume() 方法。當任何一個條件觸發(fā)時,請求會重新提交給 servlet(通過 filter 鏈)。這樣,整個請求被"重播"直到 RetryRequest 異常不再拋出,然后繼續(xù)按正常情況執(zhí)行。


此,在 BlockingServlet 和 ContinuationServlet 兩種情況中,請求被放入隊列中以訪問單個 servlet 線程。然而,雖然 servlet 線程執(zhí)行期間 BlockingServlet 發(fā)生兩秒暫停,SelectChannelConnector 中的 ContinuationServlet 的暫停發(fā)生在 servlet 之外。ContinuationServlet 的總吞吐量更高一些,因為 servlet 線程沒有將大部分時間用在 sleep() 調用中。


使 Continuations 變得有用

現(xiàn)在您已經(jīng)了解到 Continuations 能夠不消耗線程就可以暫停 servlet 請求,我需要進一步解釋 Continuations API 以向您展示如何在實際應用中使用。

resume() 方法生成一對 suspend()。可以將它們視為標準的 Object wait()/notify() 機制的 Continuations 等價體。就是說,suspend() 使 Continuation(因此也包括當前方法的執(zhí)行)處于暫停狀態(tài),直到超出時限,或者另一個線程調用 resume()。suspend()/resume() 對于實現(xiàn)真正使用 Continuations 的 Comet 風格的服務非常關鍵。其基本模式是:從當前請求獲得 Continuation,調用 suspend(),等待異步事件的到來。然后調用 resume() 并生成一個響應。

然而,與 Scheme 這種語言中真正的語言級別的 continuations 或者是 Java 語言的 wait()/notify() 范例不同的是,對 Jetty Continuation 調用 resume() 并不意味著代碼會從中斷的地方繼續(xù)執(zhí)行。正如您剛剛看到的,實際上和 Continuation 相關的請求被重新處理。這會產(chǎn)生兩個問題:重新執(zhí)行 清單 4 中的 ContinuationServlet 代碼,以及丟失狀態(tài):即調用 suspend() 時丟失作用域內所有內容。

第一個問題的解決方法是使用 isPending() 方法。如果 isPending() 返回值為 true,這意味著之前已經(jīng)調用過一次 suspend(),而重新執(zhí)行請求時還沒有發(fā)生第二次 suspend() 調用。換言之,根據(jù) isPending() 條件在執(zhí)行 suspend() 調用之前運行代碼,這樣將確保對每個請求只執(zhí)行一次。在 suspend() 調用具有等冪性之前,最好先對應用程序進行設計,這樣即使調用兩次也不會出現(xiàn)問題,但是某些情況下無法使用 isPending() 方法。Continuation 也提供了一種簡單的機制來保持狀態(tài):putObject(Object) 和 getObject() 方法。在 Continuation 發(fā)生暫停時,使用這兩種方法可以保持上下文對象以及需要保存的狀態(tài)。您還可以使用這種機制作為在線程之間傳遞事件數(shù)據(jù)的方式,稍后將演示這種方法。




DWR 2 最新引入了 Reverse Ajax 概念。這種機制可以將服務器端事件 “推入” 到客戶機??蛻舳?DWR 代碼透明地處理已建立的連接并解析響應,因此從開發(fā)人員的角度來看,事件是從服務器端 Java 代碼輕松地發(fā)布到客戶機中。

DWR 經(jīng)過配置之后可以使用 Reverse Ajax 的三種不同機制。第一種就是較為熟悉的輪詢方法。第二種稱為 piggyback,這種機制并不創(chuàng)建任何到服務器的連接,相反,將一直等待直至發(fā)生另一個 DWR 服務,piggybacks 使事件等待該請求的響應。這使它具有較高的效率,但也意味著客戶機事件通知被延遲到直到發(fā)生另一個不相關的客戶機調用。最后一種機制使用長期的、 Comet 風格的連接。最妙的是,當運行在 Jetty 下時,DWR 能夠自動檢測并切換為使用 Contiuations,實現(xiàn)非阻塞 Comet。

public void onCoord(GpsCoord gpsCoord) {

  // Generate JavaScript code to call client-side
  // function with coord data
  ScriptBuffer script = new ScriptBuffer();
  script.appendScript("updateCoordinate(")
    .appendData(gpsCoord)
    .appendScript(");");

  // Push script out to clients viewing the page
  Collection<ScriptSession> sessions = 
            sctx.getScriptSessionsByPage(pageUrl);
            
  for (ScriptSession session : sessions) {
    session.addScript(script);
  }   


public void onCoord(GpsCoord gpsCoord) {

  // Generate JavaScript code to call client-side
  // function with coord data
  ScriptBuffer script = new ScriptBuffer();
  script.appendScript("updateCoordinate(")
    .appendData(gpsCoord)
    .appendScript(");");

  // Push script out to clients viewing the page
  Collection<ScriptSession> sessions = 
            sctx.getScriptSessionsByPage(pageUrl);
            
  for (ScriptSession session : sessions) {
    session.addScript(script);
  }   


window.onload = function() {
  dwr.engine.setActiveReverseAjax(true);
}

function updateCoordinate(coord) {
  if (coord) {
    var li = document.createElement("li");
    li.appendChild(document.createTextNode(
            coord.longitude + ", " + coord.latitude)
    );
    document.getElementById("coords").appendChild(li);
  }
}

不使用 JavaScript 更新頁面
如果希望最小化應用程序中使用的 JavaScript 代碼的數(shù)量,可以使用 ScriptSession 編寫 JavaScript 回調:將 ScriptSession 實例封裝在 DWR Util 對象中。該類將提供直接操作瀏覽器 DOM 的簡單 Java 方法,并在后臺自動生成所需的腳本。 



tomcat5:客戶端連接到達 -> 傳統(tǒng)的SeverSocket.accept接收連接 ->  從線程池取出一個線程 -> 在該線程讀取文本并且解析HTTP協(xié)議 -> 在該線程生成ServletRequest、ServletResponse,取出請求的Servlet -> 在該線程執(zhí)行這個Servlet -> 在該線程把ServletResponse的內容發(fā)送到客戶端連接 -> 關閉連接。
  
  我以前理解的使用nio后的tomcat6:客戶端連接到達 -> nio接收連接 -> nio使用輪詢方式讀取文本并且解析HTTP協(xié)議(單線程) -> 生成ServletRequest、ServletResponse,取出請求的Servlet -> 直接在本線程執(zhí)行這個Servlet -> 把ServletResponse的內容發(fā)送到客戶端連接 -> 關閉連接。
  
  實際的tomcat6:客戶端連接到達 -> nio接收連接 -> nio使用輪詢方式讀取文本并且解析HTTP協(xié)議(單線程) -> 生成ServletRequest、ServletResponse,取出請求的Servlet -> 從線程池取出線程,并在該線程執(zhí)行這個Servlet -> 把ServletResponse的內容發(fā)送到客戶端連接 -> 關閉連接。
  
  
  
  從上圖可以看出,BIO與NIO的不同,也導致進入客戶端處理線程的時刻有所不同:tomcat5在接受連接后馬上進入客戶端線程,在客戶端線程里解析HTTP協(xié)議,而tomcat6則是解析完HTTP協(xié)議后才進入多線程,另外,tomcat6也比5早脫離客戶端線程的環(huán)境。
  
  實際的tomcat6與我之前猜想的差別主要集中在如何處理servlet的問題上。實際上即使拋開ThreadLocal的問題,我之前理解tomcat6只使用一個線程處理的想法其實是行不同的。大家都有經(jīng)驗:servlet是基于BIO的,執(zhí)行期間會存在堵塞的,例如讀取文件、數(shù)據(jù)庫操作等等。tomcat6使用了nio,但不可能要求servlet里面要使用nio,而一旦存在堵塞,效率自然會銳降。 

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多