总结:当我[myMOC mergeChangesFromContextDidSaveNotification:notification]
在多线程场景中调用时,我的应用程序挂起。
详细情况是这样的:
我的应用程序从服务器下载一大堆数据,并在首次启动时将其存储在 Core Data 中。它分为几个部分。解析整个事情需要几秒钟,大部分时间都花在了其中的两个块上。所以为了加快速度,我已经并行化了这两个块。这是它的样子:
NSArray *arr = [self parseJsonData:downloadedNSData]; //turns NSData into JSON array
//using NSJSONSerialization
NSMutableArray __block *first = [[NSMutableArray alloc]init];
NSMutableArray __block *second = [[NSMutableArray alloc]init];
//put half of arr in first and half in second with a loop
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dipatch_group_create();
dispatch_group_async(group, queue, ^
{
for (id element in first)
{
[MyDataClass parseData:element]; //create NSManagedObject subclass, save
}
[self saveContext];
});
dispatch_group_async(group, queue, ^
{
for (id element in second)
{
[MyDataClass parseData:element]; //create NSManagedObject subclass, save
}
[self saveContext];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
[self saveContext]
呼吁save
MOC。这当然是在多个线程上完成的,所以我需要ManagedObjectContext
为每个线程创建一个单独的。这是通过通过此对象 ( self
) 上的属性公开 MOC 来实现的,该属性维护一个NSMutableDictionary
线程名称 (call description
on NSThread
) 给NSManagedObjectContext
s。访问时,如果没有 的 MOC [NSThread currentThread]
,它会创建一个新的,将其添加到字典中并存储它。创建每个 MOC 时,我都会订阅其更改通知:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification object:createdMOC];
在mergeChanges
中,我遍历我的上下文字典并调用mergeChangesFromContextDidSaveNotification
所有上下文字典,除了发生这种情况的线程的字典。更具体地说,我[performSelector:onThread:withObject:waitUntilDone:]
曾经让每个 MOC 在为其创建的线程上执行此操作。
我也在使用NSLock
the[myMOC save]
和 mymergeChanges
方法进行锁定。如果我没有锁定这些,我会得到“Cocoa error 133020”,这显然意味着合并更改时出错。
所以,这就是我的日志记录告诉我正在发生的事情:
- 线程 1 获取要保存的锁并开始保存
- 合并上下文通知出现在线程 1 上。线程 1 获取用于合并更改的锁并开始该过程。它为主线程合并 MOC 的更改,然后在为后台线程执行 MOC 之一时挂起。
- 线程 2 开始保存但从未获得保存锁,因为另一个线程在尝试合并更改时被卡住了。
那么,为什么在合并更改时它会挂起?有没有更好的方法来处理这种情况?
更新:我尝试[persistentStoreCoordinator lock]
在我的[MOC save]
通话中使用而不是仅使用 锁定NSLock
,但无济于事。我还尝试在其中一个[NSThread sleepForTimeInterval:2]
调用中添加调用,但没有帮助。[self saveContext]
dispatch_group_async
更新 2:也许这里更好的问题是为什么我会遇到合并冲突(Cocoa 错误 133020)。这是预期的吗?我是否正确进行了合并(合并到除了一个保存之外的所有上下文)?
更新 3:我发布了另一个问题,以解决我如何进行多线程处理的更大背景。