2015-03-31 29 views
0

我试图迁移一个核心数据数据库领域(介于0-2万行),并且正在到一个死锁时,据我可以告诉,不该”不会发生。串行队列结果的核心数据堆栈中的僵局

从Singleton类,我发起这样的迁移:

_queue = dispatch_queue_create("DiagnosticMigrationQueue", NULL); 
    dispatch_async(_queue, ^{ 
     _realmMigrator = [[CoreDataToRealmMigrator alloc] init]; 
     [_realmMigrator performMigrationToRealm]; 
    }); 

performMigrationToRealm方法,我建立了核心数据堆栈正是如此:

- (void) performMigrationToRealm 
    { 
    self.migrationIsRunning = YES; 

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"persistentStore"]; 

    NSError *error; 

    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
    context.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; 
    [context.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
               configuration:@"DiagnosticData" 
                  URL:url 
                 options:nil 
                 error:&error]; 

了解检查 :当我创建队列时,还没有设置Core Data堆栈。因此,NSManagedObjectContext仅在GCD决定放置我的块时创建。

到目前为止,一切都很好。没问题。我现在运行一个方法 - 批量100,000 - 抓取实体中的所有NSManagedObjectIds。它看起来是这样的:

for (NSInteger numberOfMigratedBatches = 0; numberOfMigratedBatches < totalNumberOfBatches; numberOfMigratedBatches++) 
{ 
    NSArray *samples = [context executeFetchRequest:fetchRequest error:&error]; 
    if (samples && !error) 
    { 
     [self transferWeightSamplesToRealmWithObjectIds:samples withContext:context]; 
    } 
    [context reset]; 
    fetchRequest.fetchOffset = batchSize * (numberOfMigratedBatches+1); 
} 

即去时髦的是在上面的代码块fetchRequest线。尽管我已经发起了一个串行队列这个过程中,我莫名其妙地结束了这一点:

Three threads stuck on the same line of code

每个那些被卡在同一行的代码,即上述fetchRequest minion_duties2线程。

这是怎么回事?我明白队列!=线程,并且GDC会将我的代码放在任何适合的线程上。但是,我不希望它会将我的代码放在三个线程上。另外,什么是com.apple.root.user-initiated-qos.overcommit?我会说这是过度承诺。我只希望这个代码运行一次!

+0

据我所知,你的代码看起来很好。如果我不得不猜测,我会说:这是几个不同的fetchRequests试图在几个不同的线程上执行,可能导致死锁。是否有任何理由你手动进行批处理,而不是让Core Data通过在NSFetchRequest上设置fetchBatchSize属性来完成它? – 2015-04-01 07:06:39

+0

恩..可能是我的一个疏忽。我还没有做过很多需要批处理的fetchRequests,所以我没有意识到Core Data可以为我做到这一点。 – churowa 2015-04-02 20:49:22

回答

0

所以,这在技术上是不是一个答案,您发布的问题,但是,它可能为你提供的方式,将让你避免你正在运行到问题(解决方法?)。

由于我的猜测是它是几个不同的提取请求试图在几个不同的线程上执行导致死锁,我建议您不要手动执行批处理,而是通过在NSFetchRequest上设置fetchBatchSize属性来做到这一点,让你的核心数据做了,因此完全避免做多取的请求,如果内存使用是一个问题,请你包裹在一个autoreleasepool块循环(我猜的内部结构有一个为transferWeightSamplesToRealmWithObjectIds:withContext:方法内循环)。

核心数据有一个名为配料&断层的概念。从Apple documentation of NSFetchRequest

如果设置一个非零批量大小,对象的集合返回 当执行分成批量抓取。是 执行当抓取,整个请求进行评估,所有 匹配的对象的身份记录,但不超过BATCHSIZE对象的数据 更将从在时间的持久性存储中获取。从执行请求返回的数组 将是一个代理对象对按需 透明故障批次。 (在数据库方面,这是一个 内存游标。)

希望这对你有所帮助。