我听到很多关于CoreData和并发性的问题。因此,我决定尝试使用虚拟代码的一些场景。我无法完全解释所有的观察结果。任何指针将不胜感激。核心数据和并发:无法解释的行为
案例1 相同的管理对象被连续在两个不同的地方,主线程和用下面的代码后台线程改变。托管对象内容保存不会执行。
观察:没有崩溃。我看到“numberOfSales”的值在“主线程”和“背景队列”中读取的值不同。他们最终变得一样,分歧,变得一样等等。所以,我猜这是“最终一致性”展现自己。
这是预期的行为?即,从多个线程对同一托管对象上下文中的对象进行更改似乎可以。
案例2 的两段代码也节省了管理对象上下文中执行到持久性存储
观察:随机崩溃。这是否意味着真正的问题是,当你尝试从多线程存储事物到持久存储?
案例3 我通过使用串行队列序列化获取请求。显示在下面的代码示例2中。
观察:没有崩溃。但我期待的连续访存请求:一个来自主线程,另一个来自后台Q.但是我看到只有其中一个执行。这是为什么发生?的代码
块在背景Q的代码
dispatch_async(backgroundQueue, ^(void) {
while (1) {
sleep(1);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (Person *info in fetchedObjects) {
NSLog(@"BackQ Name: %@, SSN: %@, Num sales = %@", info.name,info.ssn, info.numberOfSales);
info.numberOfSales = @(2);
}
//In case 1: The save to persistent store part below is commented out, in case 2: this part exists
if (![self.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
}
});
块在主线程执行的处理
while (1) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"(name = %@)",@"XXX"]] ;
NSError *error;
NSArray <Person *>*fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
fetchedObjects[0].numberOfSales = @([fetchedObjects[0].numberOfSales integerValue] + 1);
NSLog(@"Fore Name: %@, SSN: %@, Num sales = %@", fetchedObjects[0].name,fetchedObjects[0].ssn, fetchedObjects[0].numberOfSales);
//In case 1: The save to persistent store part below is commented out, in case 2: this part exists
if (![self.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
}
代码示例2
self.coreDataQ = dispatch_queue_create("com.smarthome.coredata.bgqueue2", DISPATCH_QUEUE_SERIAL);
代码示例2:代码在后台Q
dispatch_async(backgroundQueue, ^(void) {
while (1) {
dispatch_async(self.coreDataQ, ^(void) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (Person *info in fetchedObjects) {
NSLog(@"BackQ Name: %@, SSN: %@, Num sales = %@", info.name,info.ssn, info.numberOfSales);
info.numberOfSales = @(2);
}
if (![self.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
});
}
});
代码示例2:代码在主线程
while (1) {
dispatch_async(self.coreDataQ, ^(void) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"(name = %@)",@"XXX"]] ;
NSError *error;
NSArray <Person *>*fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
fetchedObjects[0].numberOfSales = @([fetchedObjects[0].numberOfSales integerValue] + 1);
NSLog(@"Fore Name: %@, SSN: %@, Num sales = %@", fetchedObjects[0].name,fetchedObjects[0].ssn, fetchedObjects[0].numberOfSales);
if (![self.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
});
}
您不能直接在后台线程中使用objectContext,如果您想实现这一点,您必须创建具有后台线程能力的子上下文。 – ogres
是的,这是我在CoreData编程指南中看到的理论。但我在实践中没有看到这一点。事实上,在代码示例2中,只有“后台队列块”中的NSLOg正在执行。 –
打开并发断言,如http://oleb.net/blog/2014/06/core-data-concurrency-debugging/中所示 - 实际上,读取整个事件 – jrturton