宽高比约束会降低性能吗?

3

简而言之:

通常,水平约束方程和垂直约束方程是独立的,但一个宽高比约束将两个维度链接起来,将两个较小的线性方程组合并成一个大的方程组。从我的理解来看,这两个较小的方程组应该比组合后的大方程组更容易解决,因此,我预计宽高比约束会降低性能。然而,对每个维度进行100次约束视图的简单测试显示性能没有差异。为什么?


问题详情:

约束是线性方程

在自动布局中,每个布局约束都是一个线性方程:

view2.attribute = multiplier * view1.attribute + constant

当所有约束条件仅有一个解时,给出了一个明确且不冲突的布局。

在方法layoutSubviews()中,系统会“解析”约束条件,即从这些约束条件计算出所有子视图的框架。任务是解决线性方程组,可以通过应用高斯算法来完成。

x和y:两个独立的方程集

只要没有涉及纵横比约束,水平和垂直维度就相互独立。因此,水平约束有一个h线性方程组,垂直约束有一个v线性方程组。这些可以分别解决。

然而,将纵横比约束添加到视图中会链接两个维度。系统不再有两个独立的线性方程组,而是必须解决一个更大的h+v线性方程组。

解决线性方程组的复杂度

由于解决一组n个线性方程的复杂度在O(n²)和O(n³)之间,取决于算法,因此解决具有h和v方程的两个系统比解决具有h+v方程的一个系统要更快。因此,我预计只要存在至少一个纵横比约束条件,解决约束条件(即layoutSubviews()方法)的过程就会明显变长。
为了弄清楚这一点,我创建了一个空样本项目,在水平和垂直轴上添加了100个视图,并适当地约束它们。然后我测量了布局过程的时间:
override func layoutSubviews() {
    let t1 = mach_absolute_time()
    super.layoutSubviews()
    let t2 = mach_absolute_time()

    print(t2 - t1)
}

然后我用一个宽高比约束替换了其中一个垂直约束,然后再次测量时间。结果几乎相同。 这是我不理解的部分。

为什么宽高比约束不会对布局性能产生不良影响?

以下是我创建和约束的视图设置。 为了更好的可视性,屏幕截图仅显示每个方向上的20个视图,而不是我测量时间时使用的100个视图。

Screenshot of the views without aspect ratio constraint Screenshot of the views with aspect ratio constraint


你能分享一下你所使用的纵横比限制的细节吗? - juanjo
当然:我只是在左上角的视图中添加了一个 view.width = view.height 约束。顶部行中的所有视图都具有 equalHeight 约束,左侧列中的所有视图都具有 equalWidth 约束。 - Mischa
你确定这些是你添加的唯一约束条件吗?是否存在其他前导或尾随约束条件,或者视图之间的水平约束条件?因为根据所描述的约束条件,我认为不可能计算出每个框架。 - juanjo
我并没有说我提到了所有的限制条件。你只是问了纵横比的限制条件。:) 当然,还有保持视图位置的限制条件,例如所有水平视图之间的尾随至前导约束和所有垂直视图之间的底部至顶部约束。 - Mischa
对不起,你是正确的。 - juanjo
2个回答

1
添加一个纵横比约束并不一定会使方程组相互依赖。使用您描述的约束条件,可以计算出顶行中所有视图的x位置和宽度的方程式,而无需先解决垂直方程式或连接方程式。一旦引擎解决了第一组方程式,它只需要用常数而不是方程组来解决y方程式,垂直视图列也是如此。
解决这些方程的引擎(我猜)有启发式方法,可以根据以前的结论提高性能,我认为还有更多。
我认为你可以强制出一种只能通过解决方程组才能解决的情况,但我担心界面构建器会显示约束错误,但我现在想不到这样的情况。

你说得对。我想我太数学化地思考这个问题了。而且从数学上来看,纵横比限制确实会在维度之间创建一个链接。但事实上:为了使一个纵横比限制“起作用”,要么约束视图的宽度,要么约束视图的高度需要由该维度中的其余约束确定。因此,有了这个知识,可能有一种方法先检查哪个维度可以在没有纵横比链接的情况下解决。 - Mischa
假设引擎已经发现x约束可以在没有纵横比约束的情况下得到解决。然后,它将解决这些水平方程,这将产生具有纵横比的视图的宽度。从这个值中,引擎可以计算出该视图的高度(作为常数),然后解决y约束。 - Mischa
一个简单的检查是否有足够的约束条件来解决某些维度的系统的方法是检查 ∑(该维度的约束条件)≥ 2 × ∑(子视图) ,因为每个视图需要每个维度两个约束条件才能定义其框架。这适用于不允许不等式约束和忽略超定系统的情况。所以实际上它可能会更加复杂......但很可能有一种方法来做到这一点,而且这可能是苹果公司的人员以某种方式实现的。 - Mischa
是的,这可能会变得非常复杂,而且我想苹果公司的工程师们已经在引擎中实现了许多启发式算法,使其运行非常快。 - juanjo

1
我不知道具体实现细节,但你的逻辑论点似乎很公正。
你描述的简单测试太基础了,无法区分计算机/处理器在小样本(如100次浏览)中完成时间或完成时间差异很小。
你的测试应该使用数千或数十万次浏览。
此外,计算机/处理器一直在做许多不同的事情,它们是并行处理的。有时这是在多个核心上完成的,但每个核心也同时执行多个不同的任务。这会影响你的结果,因为你不知道在计时时发生了什么。
你的测试应该运行数千或数十万次。
因此,如果增加测试的“复杂性”和需要解决的方程数量,那么你应该开始看到解决这些方程的相对成本差异。

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Mischa
不管怎样,可能真的没有太大的区别,布局算法和我想象中有很大不同,或者这只是一个不适合测试布局性能的例子,即使有4000个视图。(如果我选择一个更高的数字,该程序最终会被杀掉,所以这几乎是我可以执行测试的最大视图数量。) - Mischa
有趣。我们不知道算法是如何构建的,或者它可能做了什么缓存,也许我们可以从你的测试中推断出一些东西,但我通常不会担心这个问题。我猜引擎中有一些东西会使你的逻辑论证无效,可能基于文本布局(再次猜测),因为它不断地结合宽度和高度。 - Wain
我同意。我会保持悬赏开放几天,希望可能有人路过并对该算法有所洞见,愿意分享一些信息。 ;) 我想我从这个测试中学到的是,当向合理数量的视图添加宽高比约束时,我们永远不需要担心性能问题 - 至少不比我们担心任何其他类型的约束更多。 - Mischa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接