1

总结:当我[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]呼吁saveMOC。这当然是在多个线程上完成的,所以我需要ManagedObjectContext为每个线程创建一个单独的。这是通过通过此对象 ( self) 上的属性公开 MOC 来实现的,该属性维护一个NSMutableDictionary线程名称 (call descriptionon NSThread) 给NSManagedObjectContexts。访问时,如果没有 的 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 在为其创建的线程上执行此操作。

我也在使用NSLockthe[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:我发布了另一个问题,以解决我如何进行多线程处理的更大背景。

4

2 回答 2

0

创建NSManagedObject子类时,会将其插入上下文中,因此只能在属于上下文的队列/线程上执行此操作。

调用-save上下文也是如此。

在我看来,从您的代码中您正在插入两个对象——每个对象都在它们自己的线程上。这是行不通的。

于 2012-09-14T15:07:07.300 回答
-1

我已经发布了这个问题,以更好地记录我的情况。我认为当前的这个问题范围有点窄。

于 2012-09-26T16:24:26.117 回答