【问题标题】:Techniques for controlling program order of execution控制程序执行顺序的技术
【发布时间】:2012-04-23 03:27:42
【问题描述】:

我正在努力解决代码“执行顺序”的概念,到目前为止,我的研究还不够。我不确定我的措辞是否不正确,这个概念可能有更合适的术语。如果有人能阐明我下面的各种绊脚石,我将不胜感激。

我明白,如果你一个接一个地调用一个方法:

[self generateGrid1];
[self generateGrid2];

两种方法都运行,但 generateGrid1 不一定要等待 generateGrid2。但如果我需要它怎么办?假设 generateGrid1 进行一些复杂的计算(需要未知的时间)并填充 generateGrid2 用于其计算的数组?每次触发事件时都需要执行此操作,而不仅仅是一次初始化。

我需要一种按顺序调用方法的方法,但有些方法要等待其他方法。我研究过回调,但在我见过的所有示例中,这个概念总是与代表结合在一起。

我也不确定何时确定我不能合理地期望一行代码被及时解析以供使用。例如:

int myVar = [self complexFloatCalculation];
if (myVar <= 10.0f) {} else {} 

我如何确定某件事是否需要足够长的时间来实施检查“在我开始我的事情之前是否完成了其他事情”。只是反复试验?

或者也许我将一个方法作为另一个方法的参数传递?它是否在执行方法之前等待对参数进行评估?

[self getNameForValue:[self getIntValue]];

【问题讨论】:

  • 编译器和/或 CPU 在符合逻辑的情况下自动优化执行顺序。例如,如果第二个调用不依赖于第一个调用,它们可能会并行运行,或者以更有效的顺序运行。如果您想要对并发执行进行更高级别和更明确的控制,您通常会考虑使用线程和/或进程,不是吗?也许你可以把你的问题更具体一点?
  • 我会研究调度队列,苹果术语中的 GCD。 iTunes 中有许多来自以前 WWDC 会议的优秀视频,可以帮助您解决这个问题。
  • (或者这是我错过的 Objective-C 概念)
  • @aaaidan:在这种情况下,您的第一条评论非常具有误导性:消息发送受编译器重新排序的影响,因为编译器可以'不知道另一端发生了什么——消息在运行时被解析。
  • @IuliusCæsar 是的,被指控有罪。我错误地将消息发送视为函数调用。

标签: objective-c arrays oop design-patterns


【解决方案1】:

我明白,如果你一个接一个地调用一个方法:

[self generateGrid1];
[self generateGrid2];

两种方法都运行,但 generateGrid1 不一定要等待 generateGrid2。但如果我需要它怎么办?

错误。 generateGrid1 将运行,然后 generateGrid2 将运行。这种顺序执行是过程语言的基础。

从技术上讲,编译器可以重新排列语句,但在最终结果可证明与原始结果无法区分的情况下。比如看下面的代码:

int x = 3;
int y = 4;

x = x + 6;
y = y - 1;

int z = x + y;
printf("z is %d", z);

x+6 还是 y-1 行先出现并不重要; 所写的代码除了计算z外,没有使用任何一个中间值,这可能以任何一种顺序发生。因此,如果编译器由于某种原因可以通过重新排列这些行来生成更高效的代码,则允许这样做。

但是,您将永远无法看到这种重新排列的效果,因为一旦您尝试使用其中一个中间值(例如,记录它),编译器就会识别出该值正在被使用,并摆脱会破坏您的日志记录的优化。

实际上,编译器不需要按照提供的顺序执行您的代码;只需生成与您提供的代码功能相同的代码。这意味着如果您将调试器附加到使用适当优化编译的程序,您实际上可以看到这些优化的效果。这会导致各种令人困惑的事情,因为调试器正在跟踪的源代码不一定与编译器生成的编译代码的代码逐行匹配。这就是为什么对于程序的调试版本几乎总是关闭优化的原因。

无论如何,关键是编译器只有在能证明没有效果的情况下才能做这些花样。 Objective-c 方法调用是动态绑定的,这意味着编译器绝对不能保证调用该方法时在运行时实际会发生什么。由于编译器无法保证会发生什么,因此编译器永远不会重新排序 Objective-C 方法调用。但是,这又回到了我之前所说的相同原则:编译器可能会更改执行顺序,但前提是用户完全察觉不到。

换句话说,不用担心。您的代码将始终自上而下地运行,每个语句都在等待它之前的语句完成。

【讨论】:

    【解决方案2】:

    一般来说,您所描述的样式中的大多数方法调用都是同步的,这意味着它们会产生您想要的效果,按照语句的编码顺序运行,其中第二个call 只会在第一次调用完成并返回之后运行

    另外,当一个方法接受参数时,它的参数在方法被调用之前被评估。

    【讨论】:

    • 哇,这对我来说是个新闻。即使第一个方法调用其他方法并花费 30 秒,第二个方法不会在第一个方法之后立即调用?即使它没有返回值?
    • 在我的第一个示例中,如果我简单地调用 generateGrid1 然后 generateGrid2,那么 generateGrid2 会使我的应用程序崩溃。大概是因为它填充的数组没有及时返回,以便 generateGrid2 使用它。但是,如果我在 generateGrid1 方法的末尾调用 generateGrid2 那就没问题了。我只是认为这是一种破解工作。
    • @Vanny 第二种方法将总是等待第一种方法完成。即使需要30年。我怀疑您的问题与您返回的数组的内存管理有关,而不是编译器为您重新排序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    • 2020-02-06
    • 2016-06-26
    • 2010-12-13
    • 2019-03-13
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多