2009-05-18 120 views
2
class ApplicationContext{ 
    private final NetworkObject networkObject = new networkObject(); 

    public ApplicationContext(){ 
     networkObject.setHost("host"); 
     networkObject.setParams("param"); 
    } 

    public searchObjects(ObjectType objType){ 
     networkObject.doSearch(buildQuery(objType)); 
    } 
} 

class NetworkObject{ 
    private final SearchObject searchObject = new SearchObject(); 

    public doSearch(SearchQuery searchQuery){ 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

考慮一個運行web應用程序的web服務器,該應用程序只創建一個ApplicationContext實例(單例)並使用相同的applicationInstance來調用searchObjects例如爲什麼多線程似乎不能加速我的web應用程序?

ApplicationContext appInstance = 
        ApplicationContextFactory.Instance(); //singleton 

到網頁上每一個新的請求,說 'search.jsp的' 發出呼叫

appInstance.searchObjects(objectType); 

我提出1000個請求爲「search.jsp的頁面。所有線程都使用相同的ApplicationContext實例,而searchObject.search()方法需要15秒才能返回。我的問題是當所有其他線程執行searchObject.search()函數或所有線程同時執行searchObject.search()時等待輪到他們(15秒)執行,爲什麼?

我希望我已經提出了我的問題非常清楚??

更新: 謝謝所有澄清我的疑問。這裏是我的第二個問題,當我這樣做應該遵守的性能有什麼區別:

public synchronized doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

OR

public doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

我相信使用功能「doSearch」沒有synchronized關鍵字,應給予更多的性能。但是,當我今天進行測試時,結果是以另一種方式出現的。當我使用同步關鍵字時,性能相似或有時更好。

任何人都可以解釋行爲。我應該如何調試這種情況。

問候,

佩裏

回答

5

那麼你有沒有指定任何同步代碼,所以沒有任何其他證據我懷疑,所有的線程將同時運行。如果SearchObject.search儘管包含一些同步,那麼顯然會限制併發性。

請注意,您的JSP容器可能使用線程池來處理1000個請求,而不是創建1000個線程。

編輯:至於爲什麼它可能會更快​​:有時併發實際上並不有助於吞吐量。諸如上下文切換,磁盤瓶頸,緩存未命中等等都會產生這種影響。這是通常不是一個好主意有更多的運行線程比核心。

對於一個真實的例子,假設你有一千個購物者都想從一個相當小的商店買東西。你會怎麼做呢?同時將所有1000件商品放在商店中,或在任何時間將商店中的商品數量保持在相當小的數量,並在外面排隊?

+0

請看我上面的更新! – pankajt 2009-05-18 14:41:47

0

就你而言,它們將全部同時執行。

如果您想防止這種情況發生,您需要進行某種同步以防止這種情況發生(例如將該方法聲明爲已同步或使用鎖定)。

ETA:

如果聲明doSearch()方法同步,只有一次一個線程就可以調用它。其他線程將阻塞,直到第一個線程結束,等待的線程將一次一個「放入」。正如你可以想象的,如果你有很多線程調用這個函數,這會殺死你的性能。

+0

請看我上面的更新! – pankajt 2009-05-18 14:42:05

0

如果你沒有同步,那麼每個線程將同時運行,而不是鎖定在鎖上。

注意

// threadsafe 

(如註釋)意味着它會與多個線程訪問它正常工作 - ,它會阻塞線程。

+0

請看我上面的更新! – pankajt 2009-05-18 14:42:09

0

它們都可以同時執行它,除非它被聲明爲同步,無論您的班級是單身人士IIRC。

+0

請看我上面的更新! – pankajt 2009-05-18 14:42:13

0

如果SearchObject.search是同步的,那麼是的。否則,試試看看。

+0

請看我上面的更新! – pankajt 2009-05-18 14:42:17

0

爲什麼需要15秒?如果它正在等待磁盤訪問並且只有一個磁盤,那麼無論您有多少線程受到磁盤搜索速度的限制。在這種情況下,更多的線程可能會更慢。

+0

我同意,如果所有線程都在等待磁盤訪問,性能會變慢。我想知道同步如何影響這裏的性能,假設search()方法需要很短的時間返回 – pankajt 2009-05-18 15:17:08

1

認識到性能與特定環境相關是明智的。在這種情況下,它可能是您的筆記本電腦或測試服務器上的軟件性能。在考慮優化代碼之前,檢查與生產環境相似的性能是明智的,因爲它們的瓶頸可能與開發機器上的瓶頸有很大不同。

作爲一個例子;當我用筆記本電腦上的大型數據庫測試我的軟件時,我總是被硬盤IO綁定。但在生產中,數據庫服務器擁有大量內存和快速磁盤,因此優化我的IO軟件不是明智之舉。

與線程類似;我的筆記本電腦中的處理器可以同時運行一個或兩個進程。擁有8個線程不會加快速度。然而,生產機器可能能夠同時處理8個螺紋。

我認爲比性能更重要的是語義。使用像同步這樣的關鍵字不僅對編譯器有用,而且對(下一個)開發者也有用。

通過使用同步,您可以與ApplicationContext上的所有其他同步方法共享鎖,也可以與searchObject無關。 就我個人而言,我非常懷疑您希望在名爲ApplicationContext的對象上進行同步。

如果searchObject不是線程安全的,我可能會推薦一個鎖定對象。這倒還口味:

public void doSearch(SearchQuery searchQuery){ 
    synchronized(searchObject) {// Only if searchObject is guaranteed to be null 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

public class ApplicationContext { 
    private SearchObject searchObject = null; 
    private final Object searchObjectLock = new Object();  

    public void doSearch(SearchQuery searchQuery){ 
     synchronized(searchObjectLock) { 
      searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
     } 
    } 
} 

不要忘了鎖每次使用searchObject,防止螺紋麻煩。使用這種細粒度的鎖定機制,您至少可以將ApplicationContext保留爲不需要searchObject相關功能的類。

在你的情況下,我不會使用任何同步,因爲它不是必需的,並且在確定瓶頸之前檢查類似生產的硬件。

如果searchObject使用數據庫,請確保數據庫屬性已編入索引並使用該索引。如果需要做1000次全表掃描,它不會很快...

+0

我同意性能是用硬件調整的。但作爲一般規則或原則,我們確實遵循了某些準則。我同意Jon關於線程數等於核心數 – pankajt 2009-05-18 20:02:27

相關問題