2009-11-26 21 views
0

前言:這已經成爲一個相當長的帖子。雖然我沒有新的節目,我有接近於零的做法各地線程,並可能需要一些幫助這裏...線程機制:在後臺準備和釋放緩存

這大概可能在短詞來描述一個共同的問題,但我有點不知所措。

一些背景第一...

我寫的iPhone代碼,我進入由於機器的緩慢性能問題。我試圖優化,以保持UI活潑,目前我正在考慮添加一些線程。

想象一下:我有一個用戶可以搜索的大型數據庫。爲了搜索,用戶切換到特定的視圖,在那裏他得到一個編輯框來輸入他的搜索文本。每當用戶在搜索框中輸入一個字符時,同步搜索並且結果立即顯示出來。

最初,數據是在sqlite數據庫中,雖然搜索準備就緒,但搜索總是需要幾秒鐘的時間,即使在線程中運行搜索時UI也會感覺遲緩,並且僅更新了結果列表一旦搜索完成幾秒鐘後。

所以我改變了搜索代碼要多快很多,這是一個十分之一秒低於現在,這意味着我有沒有延遲搜索輸入過程中的任何更多。

問題在於,爲了快速搜索,我需要在開始搜索之前做一些冗長的編寫準備。準備工作需要1-2秒。它會在內存中創建大量的對象,如果不需要,我不想保留這些對象。

所以我運行一個線程的編寫,期間的時間當搜索視圖出現。這些大部分都是動畫,所以準備工作可以在沒有用戶注意的情況下同時完成。

如果搜索視圖被卸載,我需要再次釋放緩存。這也需要一段時間(最新型號大約是1/2),所以我想在一個線程中執行此操作,否則切換到另一個視圖會有明顯的延遲。

所有這一切似乎並不難,乍一看。我有兩個功能來準備和釋放的緩存,它看起來像這樣:

- (void) internalPrepareCache 
{ 
NSAutoreleasePool *pool = nil; 
if (![NSThread isMainThread]) pool = [[NSAutoreleasePool alloc] init]; 
[cacheLock lock]; 
if (!cacheReady) { 
    Load Data Cache...; // can take a while 
    cacheReady = true; 
} 
[cacheLock unlock]; 
[pool release]; 
} 

- (void) internalReleaseCache 
{ 
NSAutoreleasePool *pool = nil; 
if (![NSThread isMainThread]) pool = [[NSAutoreleasePool alloc] init]; 
[cacheLock lock]; 
if (!cacheReady) { 
    Release Data Cache...; // can take a while 
    cacheReady = false; 
} 
[cacheLock unlock]; 
[pool release]; 
} 

然後,有獲得通過視圖控制器調用的函數,從主線程:

// this gets called by the view controller when loaded: 
- (void) threadedPrepareCache 
{ 
[NSThread detachNewThreadSelector:@selector(internalPrepareCache) toTarget:self withObject:nil]; 
} 

// this gets called by the view controller upon unload: 
- (void) threadedReleaseCache 
{ 
[NSThread detachNewThreadSelector:@selector(internalReleaseCache) toTarget:self withObject:nil]; 
} 

// this gets called by the view controller to perform a search 
- (void) searchUsingCache:... 
{ 
[self internalPrepareCache]; 
Perform the search ... 
} 

由於代碼顯示,我正在使用一個全局NSLock對象,我用它來包裝緩存準備和緩存釋放代碼的鎖定和解鎖調用。我也有一個全局狀態變量,告訴緩存是否準備好。

它變得複雜,因爲兩種特殊情況:

1)用戶可以非常快速地切換搜索視圖和反覆發作。這可以排隊幾個緩存準備和緩存釋放操作,直到緩存開始準備的時間點,而用戶的最後一個操作是關閉搜索。我喜歡避免這種情況。如果用戶速度很快(或者iPhone非常慢)並且在緩存準備線程完成之前已經進入搜索,那麼非線程搜索需要等待緩存準備就緒。我擔心這也可能與(1)中的排隊行爲發生衝突。

3)我做了如下試驗:

[self threadedPrepareCache]; 
[self threadedReleaseCache]; 
[self threadedPrepareCache]; 
[self threadedReleaseCache]; 

該測試顯示,我打算訂單未遵循:釋放首先發生(如果沒有什麼尚未公佈)。這是一個極端的例子,但它告訴我,我的上述情況可能還沒有正確編程,而且當我打算在最後一次調用時釋放它時,我最終還是會做最後的準備。

我該如何解決這個問題?

我在想另一個聲明當前所需緩存狀態的全局變量:它是由主線程的函數設置的,它要求緩存被準備或丟棄。然後,兩個線程函數中的鎖定保護代碼檢查當前所需的狀態並相應地執行操作。這可以防止不必要的情況(1),對嗎?但是,我如何確保周圍沒有競爭條件?沒有必要鎖定這個期望狀態變量的設置,是嗎?

我是否必須擔心(2)?目前,搜索功能總是同步調用internalPrepareCache(從主線程),因此等待它準備就緒。那安全嗎?

回答

1

道歉,如果這是關閉基地,即使我通讀你的文章多次。

我想你會想爭取什麼是以下幾點:

  • 保持高速緩存準備/擊穿工作過的主線程,因爲UI體驗相當多在主線程中完成而且你不想讓這種情況下降。

  • 能夠發出緩存準備線程,因爲反覆無常的用戶決定返回之前需要終止緩存準備線程,並且已經準備好線程負責自行清理,因爲它正在中止,或者通過調用同一線程中的清理工具,或者自己完成工作。

所以請嘗試使用[MyObj中performSelectorInBackground ...]啓動緩存準備和螺紋的方法應該監測它,你可以從你的UI代碼中設置屬性來告訴它停止/中止在該情況視圖正在卸載。當展開(清除緩存)時,也可以在後臺執行該操作,但要考慮這種或那種方式,以確定設置是否中止以及是否會自行清理。

最終,昂貴的東西應該脫離主線程,並在用戶界面和支持線程之間進行恰當的信號傳遞。

+0

首先,感謝你用心地理解我的帖子:) 閱讀「工作隊列」蘋果的文檔後,我也意識到,我需要一種方法取消冗長的準備代碼。 – 2009-11-27 09:57:47

+0

Apple Doc's:有趣的睡前閱讀... – wkw 2009-11-27 13:59:55

0

蘋果的「併發編程指南」幫我到底,尤其是操作隊列的理念,以「序列化調度」:

我需要的是一個單一的任務,它具有操作的隊列進行(準備,版本),所以它按順序執行它們。

我還需要一種方法來檢查當前操作是否爲準備操作。最後,我在準備功能中添加了一些檢查,以檢查是否被要求提前取消其工作。

我把它和一個函數結合起來等待一個操作的完成和清除當前隊列,現在我已經有了一個很好的工作解決方案。

我想我的問題寫在這裏只是解決方案的一半。 所以,感謝您的耐心;)