Swift Playground 执行速度

14

有没有办法提高Playground的执行速度?我想迭代多个周期而不必等待10分钟。

例如:

import UIKit

var count = 0
for var i = 0; i < 1000000000; i++ {
    count++
}

这段代码执行时间太长了,但我希望能够快速得到结果。


也许一个优化编译器可以将该代码简化为:var count = 1000000000 - zaph
3
这个网站上疯狂的关闭投票确实成为了一个问题。很棒的问题,感谢您发布它。 - Fattie
@Zaph - 你肯定明白这只是典型的测试代码示例吧???Zakh - 再次感谢你提出这个问题。 - Fattie
4
我建议你不要在游乐场这样做。我认为苹果打算让游乐场用于测试小片段和想法,而不是运行任何东西一百亿次。由于每次编辑代码都会重新执行它,并且有实时显示值等功能,我真的看不出有人能够使它快速运行一百亿次,即使是相当琐碎的事情。正如其他人所观察到的那样,一个优化编译器会直接终止你的循环,并且许多其他优化器的特性将使游乐场的“实时视图”成为不可能。 - Matt Gibson
2
我使用Playgrounds不是为了测量性能,而是进行一些计算。这个问题是一个有效的问题。 - Kartick Vaddadi
显示剩余4条评论
4个回答

9

最大的性能杀手之一是游乐场右侧的输出。现在我将向您展示如何最小化此输出。

请查看示例代码结尾。


最佳性能

最有效的方法是将所有关键性能代码放在播放器中Sources文件夹内的.swift文件中。

注意:为了使用来自Sources文件夹的函数、类、属性和方法,必须将它们标记为public。如果想要子类化一个类,则必须将其标记为open


良好的性能但丑陋的代码

以下方法(我认为这不是官方/预期的)可用于禁用游乐场输出,但也会导致丑陋的代码。然而,它适用于临时禁用输出。

有两种主要方法(和两个技巧)可以实现最小量的输出(如果您找到更好的方法,请告诉我们):

  1. Use parenthesis around Void (or Void?) expressions like assignments (normally leads to no output, see also 3.).

    var x = 0       // output: 0
    (x = 1)         // NO output
    (x = 2 * x - 1) // NO output
    (x.negate())    // NO output
    

    Note: In Swift an assignment returns Void and in case of optional chaining it is Void?.

    var x: (Int, Int)? = nil
    if (x?.0 = 0) != nil {
        // assignment was successful (x!=0 and now x=(0, x.1))
    } else {
        // assignment was not successful (x==nil)
    }
    
  2. Initialize and declare variables separately.

    var x: Int // NO output
    (x = 0)    // NO output
    
  3. If 1. does not work add an additional no-op (no operation) line above or below ().

    This happens in single line closures (and probably in some other contexts) for example: (see also the code below)

    [1, 4, 5, 6].mmap{
        () // without this line the line below would yield to an output
        ($1 = $0 + 1)
    } as [Int]
    
  4. Instead of wrapping every line in parenthesis you can also use a tuple of all the expressions which is then assigned to a variable:

    var a: Any // this may be a useful definition in this context
    var x: Int
    var y: Int
    (a = (x = 0,
          y = 1,
          x = y + 1,
          y = x*x))
    

    However this could lead to a indentation disaster...

无效的情况(我找不到删除输出的方法;此列表可能不完整):

  1. 在函数和闭包中的 return
  2. 声明可选变量,例如:var x: Int?

Sequence 上新的 map 方法示例

用法:请参考上面的第3点。

Sequence.map 的签名为:

func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]

由于我还没有找到删除return输出的方法,因此可以使用带有inout参数的闭包(通过赋值获取“返回”值)。可能的签名如下:

func mmap<U>(_ transform: (Element, inout U?) -> ()) -> [U]

所以我们可以在 inout 参数中传递 nil,因为它是每个可能的 U 的良好默认值,而不会对 U 施加任何约束,这可能需要一个实例生成器(例如:init() { ... })。

不幸的是,Swift 很难推断出 U,因此您需要使用显式类型注释帮助编译器。此外,侧边栏中 var newElement: U? 确实返回 nil

现在我将使用 Any 而不是 U?

extension Sequence {
    // ATTENTION: this is not as performant as the normal `map`!
    func mmap<U>(transform: (Element, inout Any) -> ()) -> [U] {
        var result: [U]
        (result = [U]())
        for element in self {
            var newElement: Any
            (newElement = 0) // some placeholder element
            (transform(element, &newElement))
            // assume the inout element to be of type `U`
            (result.append(newElement as! U))
        }
        return result // the ONLY output in this method
    }
}

你的示例代码

使用 Swift 4

var count = 0
for i in 0..<1_000_000_000 {
    (count += 1)
    if count % 100_000 == 0 {
        // print only every 100_000th loop iteration
        print(count)
    }
}

没有括号:大约每秒执行10,000个循环迭代

有括号:每秒执行约10,000,000个循环迭代!!!


5

我理解你的痛苦,我曾经尝试将2D函数打印到[Double],然后转换为UIImageView。其中一个步骤是迭代数百万个像素,这需要很长时间。

任何计算密集、重复或潜在耗时的任务都应该放在playground的"Sources"文件夹中。这样,在运行playground之前代码就已经被预编译了。将那个for循环的输出放在一个公共函数中,你可以从playground中调用它。这样你就不必坐在那里看着playground数遍历for循环的次数了。


0

我曾经遇到过这样的问题,但是经过数天的尝试,我已经解决了它。我所需要做的就是将所有代码移动到playground的Sources文件夹中。这样一来,执行速度就得到了提升。

希望这能对你有所帮助。

注意:不要忘记使用开放类。


0
为了加快Xcode Playground的构建速度并防止加载图标永远旋转不停:
1. 在右侧边栏中,将iOS更改为macOS在Playground设置中 2. 不要导入UIKit,而是导入Foundation (如果你不打算使用UIKit框架的特定功能,这样做就可以)

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