2015-03-31 31 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對象的數據 更將從在時間的持久性存儲中獲取。從執行請求返回的數組 將是一個代理對象對按需 透明故障批次。 (在數據庫方面,這是一個 內存遊標。)

希望這對你有所幫助。