2012-11-14 48 views
1

我們有需要做一些取一個後臺線程..但它並不需要任何數據 - 只有我們這樣做是使用特定的新的ObjectID是NSPersistentStoreCoordinator executeRequest沒有任何背景下,安全地獲取_objectIDs_

原本爲此創建空白託管上下文。

NSFetchRequest *request = [DKDocumentDetails requestAllWithPredicate:predicate inContext:ctx]; 
[request setResultType:NSManagedObjectIDResultType]; 
self.objectIDs = [DKDocumentDetails executeFetchRequest:request inContext:ctx]; 
... 

但最近我發現了,我也能做到這一點的PST本身,沒有任何背景因爲我不希望被管理對象,但只標識

NSFetchRequest *request = [DKDocumentDetails requestAllWithPredicate:predicate inContext:mainctx /*used in the wrong thread but only for getting entity description*/]; 
[request setResultType:NSManagedObjectIDResultType]; 

NSError *error = nil; 
self.objectIDs = [pst executeRequest:request inContext:nil error:&error]; 
... 

所以在我的測試中,它從來沒有墜毀,並在文檔中,我不明白爲什麼它不應該工作...我的意思是我沒有得到未保存的東西,我不能得到的對象,但用這種方式...

它更快,看起來優雅,但它安全還是不安全?

回答

3

我一直在想你的問題整天。這是我想出的。正如其他人指出的,NSPersistentStoreCoordinator對象不是線程安全的。當各個線程上的一堆NSManagedObjectContext對象使用相同的NSPersistentStoreCoordinator時,他們通過鎖定和解鎖NSPersistentStoreCoordinator來完成此操作。

但是,您只是在讀取數據,並且在線程安全的NSManagedObjectID數據。這可以嗎?

好了,Apple documentation On Concurrency with Core Data提到類似的東西你在做什麼:

For example, you can configure a fetch request to return just object IDs but also include the row data (and update the row cache)—this can be useful if you're just going to pass those object IDs from a background thread to another thread.

好,但我們需要鎖定協調?

There is typically no need to use locks with managed objects or managed object contexts. However, if you use a single persistent store coordinator shared by multiple contexts and want to perform operations on it (for example, if you want to add a new store), or if you want to aggregate a number of operations in one context together as if a virtual single transaction, you should lock the persistent store coordinator.

這似乎很清楚,如果你正在從一個以上的線程執行持久存儲操作,你應該鎖定它。

但等 - 這些只是讀取操作,它們不應該是安全的嗎?那麼,顯然不是:

Core Data does not present a situation where reads are 「safe」 but changes are 「dangerous」—every operation is 「dangerous」 because every operation has cache coherency effects and can trigger faulting.

它的緩存我們需要擔心。這就是爲什麼你需要鎖定 - 一個線程中的讀取可能導致另一個線程中的數據因無意中的緩存更改而變得混亂。你的代碼永遠不會給你帶來問題,因爲這可能非常罕見。但它的那些邊緣情況和1-in-1,000,000錯誤可以造成最大的損害...

那麼,安全嗎?我的回答:

  • 如果沒有其他人在閱讀時使用持久存儲協調器,那麼您是安全的。
  • 如果您還有其他人使用相同的持久性存儲協調器,請在獲取對象ID之前將其鎖定。
  • 使用託管對象的上下文意味着鎖定自動照顧你,所以它也是一個很好的可能性,但它看起來像你不需要需要使用它(我同意這是很好的不做一個只是爲了獲得一些對象ID)。
+0

這寫的很好,你引用文件強調你的觀點..並放棄像這樣我認爲它有資格作爲有效的答案:)謝謝:) –

+0

我會鎖定(只是爲了安全:D) –

+0

謝謝,我很高興我能幫上忙! – redlightbulb

1

從NSPersistentStoreCoordinator文檔:

Note that if multiple threads work directly with a coordinator, they need to lock and unlock it explicitly.

我要說的是,如果你正確地鎖定PSC:

[pst lock]; 
self.objectIDs = [pst executeRequest:request inContext:nil error:&error]; 
[pst unlock]; 

這將被認爲是「安全」,根據我的文檔的閱讀。也就是說,由MOC內部完成的鎖定可能是您所描述的兩種方法之間最顯着的性能差異,如果是這種情況,您可能更願意僅使用空白MOC,因爲當您或某人不太感到意外時否則會在稍後遇到代碼。

相關問題: Is NSPersistentStoreCoordinator Thread Safe?

1

沒有一個很好的理由不使用管理對象上下文此。託管對象上下文會爲您帶來很多收入 - 它處理變更管理,線程等。使用持久存儲協調器會直接失去很多這種功能。例如,如果您有尚未保存到該商店的更改,則可能會直接使用持久存儲協調器而錯過它們。

現在你說這對你有吸引力的原因是你只需要管理對象ID。看起來你真正想要的是找到管理對象,但不能對它們進行火警。你可以在你的獲取請求上使用NSManagedObjectResultType或NSManagedObjectIDResultType來完成此操作。在NSManagedObjectResultType的情況下,您只需訪問您獲取的對象上的objectID,這不會引發錯誤 - 因此不會「獲取數據」。如果行緩存已經填充,這可以具有一些性能優勢,等等。

有了所有這些說明,爲什麼不使用父子上下文來解決這個問題呢?

+0

好吧,我不想開火的故障......多數民衆贊成在正確的但我不想要的對象...我不需要任何上下文帶到桌上。 :D –

+0

重點主要是:我不想招致管理對象上下文的開銷。好吧..我當然不怕恐怕有性能問題,但對我來說,似乎...自然要向PST詢問身份證號碼:D - 我覺得我獨自一人,儘管如此^^ –

+0

一旦實施鎖定等等,在「開銷」中的區別將大致相同,並且可能會贊成使用託管對象上下文。在實現了持久性商店之前,我可以告訴您,您的解決方案在用戶手中可能存在穩定性問題。 – quellish