Swift似乎比循环中的Objective-C慢

Lup*_*rus 5 swift

我正在尝试将一些代码从Objective-C移植到Swift,我用它来解析HTML文档.我基本上使用NSXMLDocument并为HTMLDocument和HTMLNode创建自己的类来带来一些额外的功能,如getElementByID等.

如果我现在比较移植的代码,Obj-C中的解析需要0.098秒,Swift中的代码需要0.49秒!我部分地评论了代码,我可以看到,它与一些循环相关,我将NSXML部分"翻译"到我自己的类中.例如:

func getElementsByTagName(tagName: String) -> HTMLNode[] {
    let xPath = ".//\(tagName)"
    let xmlNodes = xmlElement.nodesForXPath(xPath, error: nil)
    var htmlNodes = HTMLNode[]()
    if xmlNodes.count > 0 {
        for element in xmlNodes as NSXMLNode[] {
            var node = HTMLNode(xmlElement: element as NSXMLElement)
            htmlNodes.append(node)
        }
    }
    return htmlNodes
}
Run Code Online (Sandbox Code Playgroud)

这是原始代码:(不要怀疑丢失if ...> 0.如果xmlNodes为nil,则Obj-C不进入for循环.Swift带来运行时错误)

- (NSArray*)getElementsByTagName:(NSString*)tagName {
    NSString *xPath = [NSString stringWithFormat:@".//%@", tagName];
    NSArray *xmlNodes = [self.xmlElement nodesForXPath:xPath error:nil];
    NSMutableArray *htmlNodes = [[NSMutableArray alloc] init];
    for (NSXMLElement *el in xmlNodes) {
        HTMLNode *node = [HTMLNode initWithXMLElement:el];
        [htmlNodes addObject:node];
    }
    return htmlNodes;
}
Run Code Online (Sandbox Code Playgroud)

这是swift的问题还是我监督一些代码错误?

ipm*_*mcc 9

请记住,这两个环境是桥接的,这意味着如果您的swift代码调用Objective-C对象,您仍然需要支付动态调度(即objc_msgSend)惩罚.在这个循环中,你循环的东西是在一个NSArray所有循环调用(可能NSFastEnumeration)仍然必须每次遍历桥.

"真正的"加速将来自纯粹迅速并且没有达到Objective-C桥的代码部分.这与旧的"C++更快"的论点完全相同.C++更快,但只有当你不经常回调到Objective-C时.

在一个理想的世界中,这里最好的策略是使用原生的swift XML解析器(此时可能不存在),并让你的模型和控制器对象都是纯粹的快速类,它们跨越边界进入边界Objective-C的.如果我们讨论的是C++而不是swift,我会说如果你将模型和控制器对象重写为本机C++对象,然后使用纯C++ XML解析器,并且仅在必须与之交互时使用Objective-C用户界面,你会期望显着的性能提升.

当swift必须与Objective-C库交互时,它不能使这些库比以前更快,所以很自然它们只能"快"或"慢".真正的胜利将来自纯粹的快速代码.你可以通过使用swift直接调用C(或C++)库来获得一些收益,但通用(即不是Apple提供的)P/Invoke故事(使用.NET字)并不十分清楚此时此刻.