swift 中的并行编程是否消除了值类型优化?

Does parallel programing in swift eliminate value type optimizations?

据我所知,swift 中的值类型可以更高效,因为它们存储在堆栈而不是堆中。但是,如果您对 DispatchQueue.syncDispatchQueue.async 进行多次调用,这是否会因为闭包存储在堆上而使值类型的好处消失?

As I understand it value types in swift can be more performant because they are stored on the stack as opposed to the heap.

有时。通常不是。例如,String 包括堆分配存储。许多值类型都有隐藏的堆分配存储(这实际上 really 很常见)。因此,对于许多类型,您可能无法获得预期的性能提升,但在许多情况下,您也不会因闭包而失去它。

值类型与行为有关,而不是性能(当然,您需要区分 value types and value semantics,它们是不同的,并且会对性能产生影响)。所以关于值类型和 DispatchQueue 的好处是你知道你不会意外地修改多个队列上的值,因为你知道你有自己的独立副本。当您支付分配到队列的开销时(经过优化,但仍然不便宜),复制值类型的额外成本可能不是主要问题。

根据我的经验,很难推断 Swift 性能,特别是由于写时复制优化。但是明显的 "value types" 可能具有隐藏的内部引用类型这一事实也使性能分析变得非常棘手。您通常必须了解并依赖可能发生变化的内部细节。要开始了解 Swift 性能,您绝对应该观看 Understand Swift Performance(可能多看几遍)。如果您从 C++ 中获得任何性能直觉,您必须为 Swift 抛弃几乎所有这些直觉。它只是做了很多不同的事情。

我怀疑您对性能指标和优化的看法并不完全符合 Swift 模型。

首先,看起来您的观点确实正确,但总的来说,术语 "stack-allocated" 和 "heap-allocated" 具有误导性。值类型可以是引用类型的一部分并且存在于堆上。同样,可能进入堆的东西实际上并不一定要进入堆:一个被证明不需要引用计数的引用计数对象可以在堆栈上分配而不被任何人注意到。在 C++ 等其他语言中,preferred terminology 是 "automatic storage" ("stack") 和 "dynamic storage" ("heap")。当然,Swift没有这些概念(它只有值类型和引用类型),但它们对描述性能特征很有用。

Escaping 闭包需要动态存储,因为它们的生命周期不能绑定到堆栈帧。但是,无论需要捕获多少变量,调用采用转义闭包的函数所付出的性能代价是统一的,因为始终会分配一个闭包,并且该闭包可以存储任意数量的值。

换句话说,您捕获的所有值类型对象都分组在一个动态分配中,并且分配内存的性能成本不会随着您请求的数量而变化。因此,您应该考虑到与转义闭包本身相关的(小的)速度成本,但该成本不会随着闭包捕获的值的数量而增加。除了不可避免的前期成本外,值类型的性能应该不会下降。

此外,正如 Rob 所说,每个重要的值类型(字符串、数组、字典、集合等)实际上都是引用类型的包装器,因此对于这些对象,值类型具有更多的语义优势而不是性能优势。