【发布时间】:2011-09-26 04:40:02
【问题描述】:
请耐心等待,这需要一些解释。我有一个类似于下面的函数。
上下文:“aProject”是一个名为 LPProject 的核心数据实体,带有一个名为“memberFiles”的数组,其中包含另一个名为 LPFile 的核心数据实体的实例。每个 LPFile 代表磁盘上的一个文件,我们要做的是打开每个文件并解析其文本,寻找指向其他文件的 @import 语句。如果我们找到@import 语句,我们希望找到它们指向的文件,然后通过添加与代表第一个文件的核心数据实体的关系,将该文件“链接”到该文件。由于所有这些都可能在大文件上花费一些时间,因此我们将使用 GCD 在主线程之外完成。
- (void) establishImportLinksForFilesInProject:(LPProject *)aProject {
dispatch_queue_t taskQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (LPFile *fileToCheck in aProject.memberFiles) {
if (//Some condition is met) {
dispatch_async(taskQ, ^{
// Here, we do the scanning for @import statements.
// When we find a valid one, we put the whole path to the imported file into an array called 'verifiedImports'.
// go back to the main thread and update the model (Core Data is not thread-safe.)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"Got to main thread.");
for (NSString *import in verifiedImports) {
// Add the relationship to Core Data LPFile entity.
}
});//end block
});//end block
}
}
}
现在,事情变得奇怪了:
此代码有效,但我发现了一个奇怪的问题。如果我在一个有几个文件(大约 20 个)的 LPProject 上运行它,它运行得很好。但是,如果我在具有更多文件(例如 60-70)的 LPProject 上运行它,它确实 NOT 正确运行。我们永远不会回到主线程,NSLog(@"got to main thread"); 永远不会出现并且应用程序挂起。但是,(这就是事情变得非常奇怪的地方)---如果我首先在小项目上运行代码,然后在大项目上运行它,一切都会完美运行。只有当我首先在大型项目上运行代码时才会出现问题。
如果我将第二条调度线更改为以下内容,那就是踢球者:
dispatch_async(dispatch_get_main_queue(), ^{
(也就是说,使用async 而不是sync 将块分派到主队列),一切正常。完美。无论项目中有多少文件!
我无法解释这种行为。任何有关下一步测试的帮助或提示将不胜感激。
【问题讨论】:
-
注意:为简洁起见,我已经编辑了“扫描”和“核心数据输入”代码片段。但是,我几乎可以肯定它们不是罪魁祸首,因为如果我将所有内容都放在一个线程上,它们就可以完美运行,并且它们在上述多线程情况下也可以完美运行(通过首先运行一个小项目来“预热”一切)和/或在主队列上使用 dispatch_async() 而不是 dispatch_sync())。
-
听起来你遇到了死锁问题
-
您应该在应用程序处于这种状态时运行样本或仪器,以查看其他线程都在做什么。如果他们陷入僵局,发生的事情应该会更加明显。
-
在哪里调用 NSManagedObjectContext -save?您是否有该通知的观察者强制它使用 performSelectorOnMainThread 响应主线程?
-
应编辑此问题以指示单个文件 I/O 发生的位置与 CoreData 查询发生的位置。就目前而言,它具有误导性。
标签: objective-c cocoa core-data grand-central-dispatch objective-c-blocks