挂起mergeChangesFromContextDidSaveNotification(和合并冲突) [英] Hang in mergeChangesFromContextDidSaveNotification (and merge conflicts)

查看:179
本文介绍了挂起mergeChangesFromContextDidSaveNotification(和合并冲突)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

总结:我在多线程场景中调用 [myMOC mergeChangesFromContextDidSaveNotification:notification] 时挂起我的应用程序。



具体情况如下:



我的应用程序从服务器下载一大堆数据,并在第一次启动时将其存储在Core Data 。它有几个部分。解析整个事情需要几秒钟,大部分时间花在两个块上。所以为了加快速度,我已经并行化这两个块。这是它的样子:

  NSArray * arr = [self parseJsonData:downloadedNSData]; //将NSData转换为JSON数组
//使用NSJSONSerialization
NSMutableArray __block * first = [[NSMutableArray alloc] init];
NSMutableArray __block * second = [[NSMutableArray alloc] init];

//用一个循环将半部分的arr放入循环中

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]; //创建NSManagedObject子类,save
}
[self saveContext];
});

dispatch_group_async(group,queue,^
{
for(id元素in second)
{
[MyDataClass parseData:element]; // create NSManagedObject子类,保存
}
[self saveContext];
});

dispatch_group_wait(group,DISPATCH_TIME_FOREVER);

[self saveContext] $ c> save 。这当然是在多个线程上完成的,所以我需要为每个线程创建一个单独的 ManagedObjectContext 。这是通过在该对象( self )上保留一个 NSMutableDictionary 调用描述 NSThread )到 NSManagedObjectContext 当访问时,如果没有用于 [NSThread currentThread] 的MOC,它将创建一个新的,将其添加到字典并存储它。当创建每个MOC时,我订阅其更改通知:

  NSNotificationCenter * center = [NSNotificationCenter defaultCenter]; 
[center addObserver:self selector:@selector(mergeChanges :)
name:NSManagedObjectContextDidSaveNotification object:createdMOC];

mergeChanges 的上下文,并调用 mergeChangesFromContextDidSaveNotification 在所有这些,除了那个线程发生这种情况。更具体地说,我使用 [performSelector:onThread:withObject:waitUntilDone:] 让每个MOC在创建的线程上执行此操作。



我也使用 [myMOC save] 和我的<$>锁定 NSLock c $ c> mergeChanges 方法。如果我没有锁定那些,我有可可错误133020,其中显然意味着错误合并更改。 / p>

所以,这是我的日志记录告诉我发生了:




  • 获取要保存的锁并开始保存

  • 线程1上有合并上下文通知。线程1获取合并更改的锁并开始该过程。

  • 线程2开始保存,但永远不会获取锁定以进行保存,因为它会为主线程合并MOC的更改,然后在执行后台线程的MOC时挂起。



那么,为什么在合并更改时会挂起?

我尝试过使用 [persistentStoreCoordinator lock] code> $ 周围的 [MOC save] 调用,而不是只有一个锁 NSLock 我还尝试在 [self saveContext] 之前添加 [NSThread sleepForTimeInterval:2]



更新2:也许更好的问题这里是为什么我得到合并冲突(可可错误133020)。这是预期的吗?

更新3:我已经发布了另一个问题,以解决我如何做多线程的更大的上下文。

解决方案

我发布了这个问题记录我的情况一点更好。这个当前的问题我认为范围有点狭窄。


In summary: My app is hanging when I call [myMOC mergeChangesFromContextDidSaveNotification:notification] in a multithreaded scenario.

The detailed situation is this:

My app downloads a whole bunch of data from a server and stores it in Core Data on first launch. It comes in several parts. Parsing the whole thing takes several seconds, and most of that time is spent on two of the chunks. So in order to speed it up, I've parallelized those two chunks. This is what it looks like:

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] calls save on the MOC. This is of course done on multiple threads, so I need to create a separate ManagedObjectContext for each thread. This is accomplished by exposing the MOC via a property on this object (self) that maintains an NSMutableDictionary of thread names (call description on NSThread) to NSManagedObjectContexts. When accessed, if there isn't a MOC for [NSThread currentThread], it creates a new one, adds it to the dictionary, and stores it. When each MOC is created, I subscribe to its change notifications:

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(mergeChanges:)
      name:NSManagedObjectContextDidSaveNotification object:createdMOC];

In mergeChanges, I loop through my dictionary of contexts and call mergeChangesFromContextDidSaveNotification on all of them except the one for the thread that this is happening on. More specifically, I use [performSelector:onThread:withObject:waitUntilDone:] to have each MOC do this on the thread it's created for.

I'm also locking using NSLock around both the [myMOC save] and my mergeChanges method. If I didn't lock around those, I got "Cocoa error 133020", which apparently means an error merging changes.

So, this is what my logging tells me is happening:

  • Thread 1 acquires the lock to save and begins saving
  • A merge context notification comes on thread 1. Thread 1 acquires the lock for merging changes and begins that process. It merges changes for the MOC for the main thread and then hangs when doing one of the MOCs for the background threads.
  • Thread 2 starts to save but never acquires the lock for saving, because the other thread is stuck trying to merge changes.

So, why is it hanging when merging changes? Is there a better way to handle this scenario?

Update: I have tried using [persistentStoreCoordinator lock] around my [MOC save] call instead of just a lock with NSLock, to no avail. I also tried adding [NSThread sleepForTimeInterval:2] before the call to [self saveContext] in one of the dispatch_group_async calls, and it didn't help.

Update 2: Perhaps the better question here is why I was getting merge conflicts (Cocoa Error 133020). Is that expected? Am I doing the merge right (merging to all contexts except the one saving)?

Update 3: I've posted another question to address the larger context of how I'm doing the multithreading.

解决方案

I've posted this question documenting my situation a little better. This current question I think is a little narrow in scope.

这篇关于挂起mergeChangesFromContextDidSaveNotification(和合并冲突)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆