gpt4 book ai didi

iphone - NSManagedObjectContext performBlockAndWait : doesn't execute on background thread?

转载 作者:IT老高 更新时间:2023-10-28 11:42:39 26 4
gpt4 key购买 nike

我有一个 NSManagedObjectContext 声明如下:

- (NSManagedObjectContext *) backgroundMOC {
if (backgroundMOC != nil) {
return backgroundMOC;
}
backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
return backgroundMOC;
}

请注意,它是用私有(private)队列并发类型声明的,因此它的任务应该在后台线程上运行。我有以下代码:
-(void)testThreading
{
/* ok */
[self.backgroundMOC performBlock:^{
assert(![NSThread isMainThread]);
}];

/* CRASH */
[self.backgroundMOC performBlockAndWait:^{
assert(![NSThread isMainThread]);
}];
}

为什么打电话 performBlockAndWait在主线程而不是后台线程上执行任务?

最佳答案

折腾另一个答案,尝试解释原因 performBlockAndWait将始终在调用线程中运行。
performBlock是完全异步的。它总是将块入队到接收 MOC 的队列中,然后立即返回。因此,

[moc performBlock:^{
// Foo
}];
[moc performBlock:^{
// Bar
}];

将在 moc 的队列中放置两个块。它们将始终异步执行。一些未知线程将从队列中取出块并执行它们。此外,这些块被包装在它们自己的自动释放池中,并且它们将代表一个完整的 Core Data 用户事件( processPendingChanges )。
performBlockAndWait不使用内部队列。它是在调用线程的上下文中执行的同步操作。当然,它会等到队列上的当前操作执行完毕,然后该块将在调用线程中执行。这是有记录的(并在几个 WWDC 演示文稿中重申)。

此外, performBockAndWait是可重入的,因此嵌套调用都发生在该调用线程中。

Core Data 工程师已经非常清楚,基于队列的 MOC 操作运行的实际线程并不重要。这是使用 performBlock* 的同步API 是关键。

因此,将“performBlock”视为“此块被放置在队列中,将在某个未确定的时间在某个未确定的线程中执行。该函数将在入队后立即返回给调用者”
performBlockAndWait是“这个块将在某个不确定的时间执行,在这个完全相同的线程中。该函数将在此代码完全执行后返回(这将在与此 MOC 关联的当前队列耗尽后发生)。”

编辑

Are you sure of "performBlockAndWait does NOT use the internal queue"? I think it does. The only difference is that performBlockAndWait will wait until the block's completion. And what do you mean by calling thread? In my understanding, [moc performBlockAndWait] and [moc performBloc] both run on its private queue (background or main). The important concept here is moc owns the queue, not the other way around. Please correct me if I am wrong. – Philip007



不幸的是,我像我那样措辞了答案,因为就其本身而言,它是不正确的。但是,在原始问题的上下文中,它是正确的。具体来说,在拨打 performBlockAndWait 时在私有(private)队列上,块将在调用该函数的线程上执行 - 它不会被放入队列并在“私有(private)线程”上执行。

现在,在我进入细节之前,我想强调,依赖库的内部工作是非常危险的。您真正应该关心的是,除了与主线程相关的任何内容外,您永远不能期望特定线程执行块。因此,期待 performBlockAndWait不建议不要在主线程上执行,因为它将在调用它的线程上执行。
performBlockAndWait使用 GCD,但它也有自己的层(例如,防止死锁)。如果您查看 GCD 代码(它是开源的),您可以看到同步调用是如何工作的 - 通常它们与队列同步并调用调用该函数的线程上的块 - 除非队列是主队列或全局队列。此外,在 WWDC 会谈中,Core Data 工程师强调了 performBlockAndWait 的观点。将在调用线程中运行。

所以,当我说它不使用内部队列时,并不意味着它根本不使用数据结构。它必须将调用与队列中已有的块以及其他线程和其他异步调用中提交的块同步。但是,在拨打 performBlockAndWait 时它不会将块放在队列中……而是同步访问并在调用该函数的线程上运行提交的块。

现在,SO 不是一个很好的论坛,因为它比这要复杂一些,尤其是主队列和 GCD 全局队列 - 但后者对于 Core Data 并不重要。

主要的一点是,当您拨打任何 performBlock* 时或者 GCD 函数,你不应该期望它在任何特定线程上运行(除了与主线程相关的东西),因为队列不是线程,只有主队列会在特定线程上运行块。

调用核心数据时 performBlockAndWait该块将在调用线程中执行(但将与提交到队列的所有内容适当同步)。

我希望这是有道理的,尽管它可能只会引起更多的困惑。

编辑

此外,您可以看到这种隐含的含义,即 performBlockAndWait 的方式。提供可重入支持打破块的 FIFO 排序。举个例子...
[context performBlockAndWait:^{
NSLog(@"One");
[context performBlock:^{
NSLog(@"Two");
}];
[context performBlockAndWait:^{
NSLog(@"Three");
}];
}];

请注意,严格遵守队列的 FIFO 保证意味着嵌套 performBlockAndWait (“三”)将在异步块(“二”)之后运行,因为它是在异步块提交之后提交的。然而,情况并非如此,因为这是不可能的......出于同样的原因,嵌套 dispatch_sync 会导致死锁。调用。如果使用同步版本,则需要注意一些事项。

一般来说,尽可能避免同步版本,因为 dispatch_sync可能导致死锁,以及任何可重入版本,例如 performBlockAndWait将不得不做出一些“错误”的决定来支持它......就像让同步版本“跳”队列一样。

关于iphone - NSManagedObjectContext performBlockAndWait : doesn't execute on background thread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11831946/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com