Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios CFRunLoopPerformBlock vs dispatch\u async_Ios_Multithreading_Grand Central Dispatch - Fatal编程技术网

Ios CFRunLoopPerformBlock vs dispatch\u async

Ios CFRunLoopPerformBlock vs dispatch\u async,ios,multithreading,grand-central-dispatch,Ios,Multithreading,Grand Central Dispatch,我在后台线程上做了一些计算工作,之后我需要更新一些calayer的转换,我尝试使用 dispatch_async(dispatch_get_main_queue(), ^{calayer.transform = newTransform}); 及 我只是觉得他们是一样的, 但我发现calayer在使用dispatch\u async时工作得非常顺利(可能?)。 这两个函数有什么不同?这里的主要区别是CFRunLoopPerformBlock允许您指定执行块的特定运行循环模式,而dispatch

我在后台线程上做了一些计算工作,之后我需要更新一些calayer的转换,我尝试使用

dispatch_async(dispatch_get_main_queue(), ^{calayer.transform = newTransform});

我只是觉得他们是一样的, 但我发现calayer在使用dispatch\u async时工作得非常顺利(可能?)。
这两个函数有什么不同?

这里的主要区别是
CFRunLoopPerformBlock
允许您指定执行块的特定运行循环模式,而
dispatch\u async(dispatch\u get\u main\u queue(),…)
仅在公共模式下执行。也许更接近您看到的性能问题,
CFRunLoopPerformBlock
不会唤醒主线程。从
CFRunLoopPerformBlock
的文档中:

此方法仅将块排队,不会自动唤醒 指定的运行循环。因此,块的执行发生在 下次运行循环唤醒以处理另一个输入源时。如果你 想要马上完成工作,你必须明确地意识到这一点 使用CFRunLoopWakeUp函数的线程

在实践中,这通常意味着直到运行循环唤醒时(即,用户事件发生、计时器触发、运行循环源触发、接收马赫消息等),才会执行块。GCD在设计上不是基于运行循环的API;主队列和主线程运行循环之间的关系实际上是一个实现细节。我希望实现能够唤醒运行循环本身,如果这对于主队列的服务是必要的


如果没有相反的信息,我强烈怀疑这是性能差异的根源。如果您在调用
CFRunLoopPerformBlock
后立即添加对
CFRunLoopWakeUp
的调用,我希望性能类似。我有时会将它们一起使用:

dispatch_async(dispatch_get_main_queue(), ^(void) {
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
        // stuff
    });
});
我使用它向主线程发送一个块,当UIScrollview滚动时,该块将在不引起“故障”的情况下执行

我最近也在使用:

CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
    // stuff
});
代替:

[self performSelector:@selector(myMethod:) withObject:myObject afterDelay:0]

以便将代码的执行推迟到下一次通过runloop。这样,我就不必创建一个特殊的方法来包含我想要执行的代码,也不必将执行的所有参数包装到一个(id)myObject中。

GCD的主队列是一个串行队列。因此,它一次只能运行一个任务。即使该任务运行内部运行循环(例如,运行模式对话框),提交到主队列的其他任务也无法运行,直到该循环完成

使用
CFRunLoopPerformBlock()
提交的任务可以在运行循环以一种目标模式运行时运行。这包括运行循环是否从使用
CFRunLoopPerformBlock()
提交的任务中运行

考虑以下示例:

CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
    printf("outer task milestone 1\n");
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
        printf("inner task\n");
    });
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("outer task milestone 2\n");
});
产生如下输出:

outer task milestone 1
inner task
outer task milestone 2
而这:

dispatch_async(dispatch_get_main_queue(), ^{
    printf("outer task milestone 1\n");
    dispatch_async(dispatch_get_main_queue(), ^{
        printf("inner task\n");
    });
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("outer task milestone 2\n");
});
产生:

outer task milestone 1
outer task milestone 2
inner task

可能导致严重问题的一个微妙之处是,发送到
CFRunLoopPerformBlock
的CF块中的一个错误并不总是按照发送顺序调用。如果订单对您的程序很重要,那么您需要找到一种自己提供订单的方法。出于这个原因以及另一个答案中提到的嵌套,
CFRunLoopPerformBlock
的文档不应使用队列术语。遗憾的是,此错误也悄悄地传播到了
NSRunLoop
的某些方法中(当然,因为它们调用
CFRunLoopPerformBlock
)。

您观察到的平滑程度的一部分可能是,在运行循环的内部,块“发送”到调度队列,而块“发送”to
CFRunLoopPerformBlock
在不同的逻辑“时刻”提供服务。当然,这在很大程度上取决于块相对于系统其余部分和应用程序的作用。您可以通过使用
NSRunLoop
提供的略高级别方法来避免调用
CFRunLoopWakeUp
,该方法为您调用
CFRunLoopWakeUp
。这意味着块“已发送”要
CFRunLoopPerformBlock
必须支持重新进入。如果我们假设我们正在发送一个块到主线程,以便能够执行与UI相关的工作,这通常在相当高的抽象级别,这是很重要的。
outer task milestone 1
outer task milestone 2
inner task