快速创建对象和setValue:forKey:

时间:2015-06-13 07:27:06

标签: swift

我正在使用目标C转换的代码访问Swift中的本地MySQL数据库。在目标C中,它的执行速度非常快,在Swift中的速度最慢可达10到15倍,具体取决于记录的数量。

我正在使用泛型来创建数据传输对象。 SQL select方法有这个签名:

func SQLSelect<T: NSObject>(select: String) -> [T]?

首先,我只从MySQL数据库中获取了20.000条记录,并以空数组Ts返回。时间需要0.3秒,但速度不快但可以接受。

然后我在上面的函数中创建了20.000个T实例并将它们附加到本地Swift数组中,这个数据很快:0.1秒。

现在从获取的MySQL数据中创建5个NSNumbers和9个字符串非常慢:1.2秒。 280.000个对象创作(14 * 20.000 = 280.000)。另外1.4秒用于使用setValue设置每个T实例的属性:ForKey:

Objective C和Xojo(aka REALbasic)中的相同代码速度很快:不到1秒,而超过3秒。

我有什么选择让Swift代码更快?

First Edit - 添加了源代码:

func SQLSelect<T: NSObject>(select: String) -> [T]? {
  ... // error handling omitted
  var statement = select.cStringUsingEncoding(NSUTF8StringEncoding)!
  var err = mysql_real_query(mysql, statement, strlen(statement))
  ... // error handling omitted
  var mysql_result: UnsafeMutablePointer<MYSQL_RES> = mysql_store_result(mysql)
  ... // error handling omitted
  var mysql_fields: UnsafeMutablePointer<MYSQL_FIELD> = mysql_fetch_fields(mysql_result)
  ... // error handling omitted
  var names = [String]()
  var types = [UInt32]()
  var columnCount = mysql_num_fields(mysql_result)
  for i: Int in 0...columnCount - 1 {
    names.append(String.fromCString(mysql_fields[i].name)!)
    types.append(mysql_fields[i].type.value)
  }
  var records = [T]()
  var recordCount = Int(mysql_num_rows(mysql_result))
  records.reserveCapacity(recordCount - 1)
  for r in 0...recordCount - 1 {
    var row = mysql_fetch_row(mysql_result)
    var record = T()
    for c: Int in 0...columnCount - 1 {
        var value: AnyObject?
        if row[c] == nil {
          value = nil;
        } else {
          switch types[c] {
          case MYSQL_TYPE_TINY.value, MYSQL_TYPE_SHORT.value, MYSQL_TYPE_INT24.value, MYSQL_TYPE_LONG.value:
              value = NSNumber(int: atoi(row[c]))
          case MYSQL_TYPE_FLOAT.value:
              value = NSNumber(float: strtof(row[c], nil))
          ... // other data types omitted
          case MYSQL_TYPE_TINY_BLOB.value, MYSQL_TYPE_BLOB.value, MYSQL_TYPE_MEDIUM_BLOB.value, MYSQL_TYPE_LONG_BLOB.value, MYSQL_TYPE_BIT.value,
                 MYSQL_TYPE_SET.value, MYSQL_TYPE_ENUM.value, MYSQL_TYPE_GEOMETRY.value, MYSQL_TYPE_VAR_STRING.value, MYSQL_TYPE_STRING.value:
              if mysql_fields[c].charsetnr == 63 {
                value = NSData(bytes: row[c], length: Int(strlen(row[c])))
              } else {
                value = String.fromCString(row[c])!
              }
          case MYSQL_TYPE_NULL.value:
              value = nil
          default:
              value = nil
          }
          record.setValue(value, forKey: names[c])
        }
    }
    records.append(record)
  }
  return records
}

第二次编辑:运行乐器中代码的结果

它显示大约40%的时间用于:

-[NSObject(NSKeyValueCoding) setValue:forKey:]

并且在该功能中更深层次主要是这三个功能:

@objc Swift._NSContiguousString.getCharacters (Swift._NSContiguousString)(Swift.UnsafeMutablePointer<Swift.UInt16>, range : C._SwiftNSRange) -> ()
_swift_retain_(swift::HeapObject*)
_swift_release_(swift::HeapObject*)

第二大时间用途是:

Swift.Array.append <A>(inout [A])(A) -> ()

因此,可能唯一的解决方案是使用Objective C代码保持对数据库的访问。

0 个答案:

没有答案