【问题标题】:Assign count variable over calling .count on Array in Swift通过调用 .count 在 Swift 中的 Array 上分配计数变量
【发布时间】:2016-12-31 23:41:59
【问题描述】:

我偶尔会遇到一个我不会更改数组内容的地方,但我需要在一个函数中多次知道它的计数。将数组的 .count 赋值给一个变量并多次使用是不是效率更高,还是编译器让效率等效?

【问题讨论】:

  • 我建议:Don't worry about it...until it's a problem。在您的分析器表明那里存在瓶颈之前,请使用您认为更具可读性的任何方式。
  • @JamesWebster 同意 10000%。在紧密的循环中,诸如此类的小事情肯定很重要,尤其是在发出保留/释放调用的情况下,但在大多数情况下,优化器会做正确的事情,而且当它不容易修复时,使用 Instruments 会很明显那些具体案例。
  • “别担心......直到它成为一个问题”不是我的工作。我是一个单独的字体端开发人员,从事为期一年的项目以制作企业应用程序。我从大学毕业后直接在一家初创公司获得了这个职位,如果我做好我的工作,这将是成功的。我必须在第一次做我能做到的所有事情上都做到完美,因为我负担不起 10 个人队所拥有的所有福利。我尽可能地写出接近完美的代码,而不是每次我需要另一层深度时都重构它。会有问题,但是这家公司和它的成功将等同于我自己的。
  • I have to do everything perfect that I can my first time around - 在很多情况下,“完美”的事情是进行微优化。例如仅对于这个问题,假设您已经花费了一个小时的时间,考虑潜在的问题,输入这个问题,阅读答案并编辑您的代码,发现您已经节省了 0.0001 秒。使用分析器来找出实际瓶颈/泄漏/其他问题存在的位置并修复它,那一小时可能会更好。
  • 我想澄清一下,我的意思不是“不要担心一切”,我的意思是“不要担心优化”。

标签: arrays swift count compiler-optimization enumeration


【解决方案1】:

让我们调查一下! myArray.count 是否等同于访问存储的属性,或者如果为非变异数组重复调用,它是否是执行一些“不必要”计算的计算属性? (忽略编译器的聪明)

/// The number of elements in the array.
public var count: Int {
  return _getCount()
}

// ... what is function _getCount()?

internal func _getCount() -> Int {
  return _buffer.count
}

// ... what is property _buffer?
internal var _buffer: _Buffer

// ... what is type _Buffer? (Swift)
internal typealias _Buffer = _ContiguousArrayBuffer<Element>

// ... what is type _ContiguousArrayBuffer?
// --> switch source file
import SwiftShims

/// Class used whose sole instance is used as storage for empty
/// arrays.  The instance is defined in the runtime and statically
/// initialized.  See stdlib/runtime/GlobalObjects.cpp for details.
internal struct _ContiguousArrayBuffer<Element> : _ArrayBufferProtocol {

  // ... conformance to _ArrayBufferProtocol

  /// The number of elements the buffer stores.
  internal var count: Int {
    get {
      return __bufferPointer.header.count
    }
    // ...
  }   
  // ...
}

// ... what is property __bufferPointer?
var __bufferPointer: ManagedBufferPointer<_ArrayBody, Element>

// what is type _ArrayBody?
// we notice for now that it is used in the following class:
internal final class _EmptyArrayStorage
  : _ContiguousArrayStorageBase {
  // ...

  var countAndCapacity: _ArrayBody // telling name for a tuple? :)
}

// --> proceed to core/ArrayBody.swift
import SwiftShims

// ...

internal struct _ArrayBody {
  var _storage: _SwiftArrayBodyStorage

  // ...

  /// The number of elements stored in this Array.
  var count: Int {
    get {
      return _assumeNonNegative(_storage.count)
    }
    set(newCount) {
      _storage.count = newCount
    }
  } 
}

// we are near our price! we need to look closer at  _SwiftArrayBodyStorage, 
// the type of _storage, so lets look at SwiftShims, GlobalObjects.cpp
// (as mentioned in source comments above), specifically
// --> switch source file
struct _SwiftArrayBodyStorage {
  __swift_intptr_t count;              
  __swift_uintptr_t _capacityAndFlags;
};

// Yay, we found a stored property!

所以最后count 是一个存储属性,不是每次调用都计算的,所以应该没有理由自己显式存储arr.count 属性。

【讨论】:

  • 我需要更好地看和看这些东西。看你做之后,就很明显了!谢谢你的帖子!!!
  • @Sethmr 乐于助人!
【解决方案2】:
struct _SwiftArrayBodyStorage {
    __swift_intptr_t count;
    __swift_uintptr_t _capacityAndFlags;
};

这是 Swift 实现的结构。根据这个计数,是否一直都知道缓冲区中有多少元素。您可能可以使用它

信息表:https://ankit.im/swift/2016/01/08/exploring-swift-array-implementation/

编辑以获取更多信息

public var count: Int {
  get {
    return __bufferPointer.value.count
  }
  nonmutating set {
     _sanityCheck(newValue >= 0)

     _sanityCheck(
        newValue <= capacity,
        "Can't grow an array buffer past its capacity")

        __bufferPointer._valuePointer.memory.count = newValue
    }
}

【讨论】:

  • “最好给变量赋值” – 为什么?
【解决方案3】:

没关系;我建议只做任何让你的代码更简单、更容易理解的事情。在发布版本中,优化器应该内联并注意值在调用之间是相同的。不管怎样,Array.count 在性能/代码生成方面基本上等同于访问局部变量。

【讨论】:

  • “Array.count 在性能/代码生成方面基本上等同于访问局部变量” – 这可能是真的,但您有任何参考资料支持您的主张吗? “基本等价”是什么意思?
【解决方案4】:

Array.count 是一个预先计算的值。由于它不会即时计算它,因此使用它比使用内存再次存储它要少得多。即便如此,这两种方法都不重要,除非在数百万以上完成。

【讨论】:

    猜你喜欢
    • 2013-11-10
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    相关资源
    最近更新 更多