我正在使用目标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代码保持对数据库的访问。