1

フェッチを行う必要があるバックグラウンド スレッドがありますが、データは必要ありません。オブジェクト ID のみです。

当初は、このためだけに特定の新しく作成された空のマネージド コンテキストを使用してこれを行いました。

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

しかし、最近私は、PST自体でこれを行うこともできることを知りました。コンテキストなしで、管理対象オブジェクトは必要なく、IDのみが必要です

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];
...

したがって、私のテストではクラッシュすることはありませんでした。ドキュメントでは、なぜ機能しないのかわかりません...つまり、保存されていないものを取得せず、オブジェクトを取得できませんが、この方法で使用されます...

より高速でエレガントに見えますが、安全でしょうか?

4

3 に答える 3

3

私はあなたの質問について一日中考えていました。これが私が思いついたものです。他の人が指摘したように、NSPersistentStoreCoordinatorオブジェクトはスレッドセーフではありません。NSManagedObjectContextさまざまなスレッド上の一連のオブジェクトが同じNSPersistentStoreCoordinatorを使用する場合、NSPersistentStoreCoordinator.

ただし、データを読み取るだけで、スレッドセーフなデータが心配NSManagedObjectIDされます。それは大丈夫ですか?

さて、Apple のドキュメント On Concurrency with Core Dataでは、あなたがしていることに似たことが言及されています。

たとえば、オブジェクト ID のみを返すだけでなく、行データも含める (および行キャッシュを更新する) ようにフェッチ要求を構成できます。これは、これらのオブジェクト ID をバックグラウンド スレッドから別のスレッドに渡すだけの場合に役立ちます。 .

わかりましたが、コーディネーターをロックする必要がありますか?

通常、管理対象オブジェクトまたは管理対象オブジェクト コンテキストでロックを使用する必要はありません。ただし、複数のコンテキストで共有される単一の永続ストア コーディネーターを使用し、それに対して操作を実行する場合 (たとえば、新しいストアを追加する場合)、または複数の操作を 1 つのコンテキストにまとめて次のように集約する場合は、仮想単一トランザクションの場合は、永続ストア コーディネーターをロックする必要があります。

複数のスレッドから永続ストアに対して操作を実行している場合は、それをロックする必要があることは明らかです。

しかし待ってください - これらは単なる読み取り操作であり、安全ではないでしょうか? まあ、明らかにそうではありません:

Core Data は、読み取りが「安全」であるが変更が「危険」であるという状況を示していません。すべての操作はキャッシュの一貫性の影響を受け、障害を引き起こす可能性があるため、すべての操作が「危険」です。

心配する必要があるのはキャッシュです。そのため、ロックする必要があります。1 つのスレッドで読み取りを行うと、別のスレッドのデータが不注意によるキャッシュの変更によって台無しになる可能性があります。これはおそらく非常にまれであるため、コードで問題が発生することはありませんでした。しかし、最もダメージを与える可能性があるのは、それらのエッジケースと 1,000,000 分の 1 のバグです...

それで、それは安全ですか?私の答え:

  • 読み取り中に永続ストア コーディネーターを使用していない場合は、安全です。
  • 同じ永続ストア コーディネーターを使用しているものが他にある場合は、オブジェクト ID を取得する前にロックしてください。
  • 管理オブジェクト コンテキストを使用すると、ロックが自動的に処理されることを意味するため、これも良い可能性ですが、それを使用する必要はないようです(そして、取得するためだけに作成しない方が良いことに同意します)いくつかのオブジェクト ID)。
于 2012-12-08T23:55:07.037 に答える
1

NSPersistentStoreCoordinator ドキュメントから:

複数のスレッドがコーディネーターを直接操作する場合は、明示的にロックおよびロック解除する必要があることに注意してください。

PSC を適切にロックするとしたら、次のようになります。

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

ドキュメントを読むと、それは「安全」と見なされます。そうは言っても、MOC によって内部的に行われるロックは、あなたが説明した 2 つのアプローチの間で最も重要なパフォーマンスの違いかもしれません。その場合は、空の MOC を使用することを好むかもしれません。それ以外の場合は、後でコードに遭遇します。

関連する質問: NSPersistentStoreCoordinator はスレッドセーフですか?

于 2012-12-07T16:53:39.320 に答える
1

これに管理対象オブジェクト コンテキストを使用しない正当な理由はありません。管理対象オブジェクト コンテキストは、変更管理、スレッド化などを処理します。永続ストア コーディネーターを直接使用すると、この機能の多くが失われます。たとえば、このストアにまだ永続化されていない変更がある場合、永続ストア コーディネーターを直接使用すると、それらを見逃す可能性があります。

これが魅力的な理由は、管理対象オブジェクト ID だけが必要だからです。あなたが本当に望んでいるように見えるのは、管理対象オブジェクトを見つけることですが、それらに障害を発生させることではありません。これは、フェッチ要求で NSManagedObjectResultType または NSManagedObjectIDResultType を使用して行うことができます。NSManagedObjectResultType の場合、取得したオブジェクトの objectID にアクセスするだけで、エラーは発生せず、「データを取得」しません。行キャッシュがすでに移入されている場合などは、これによりパフォーマンスが向上する可能性があります。

以上のことから、これを解決するために親子コンテキストを使用しないのはなぜでしょうか?

于 2012-12-08T21:57:56.900 に答える