我正在进行像素处理,当我调用一个空的Objective-C方法时,它会使用多25%的CPU。
另外一个奇怪的现象是,如果我在该方法中有另一个永远不会被调用的Obj-C函数调用,它会使CPU使用量增加10%。
这是我正在调用的代码:
- (void)addLeftCorner:(struct Position)p top:(BOOL)top {
if (top) {
[blackBorderLock lock];
[topLeftAllyMinionCorners addObject:[NSValue valueWithBytes:&p objCType:@encode(struct Position)]];
[blackBorderLock unlock];
} else {
[blackBorderLock lock];
[bottomLeftAllyMinionCorners addObject:[NSValue valueWithBytes:&p objCType:@encode(struct Position)]];
[blackBorderLock unlock];
}
}
- (void) processPixel:(uint8_t *)pixel x:(int)x y:(int)y{
//Assume multithreaded
if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) {
//Check if top left border
if (x < imageData.imageWidth-1) {
if (y < imageData.imageHeight-1) { //Check for top left bar
//Check bottom right pixel
uint8_t *bottomRightPixel = pixel + (imageData.imageWidth + 1)*4;
if (bottomRightPixel[2] == 81 && bottomRightPixel[1] == 162 && bottomRightPixel[0] == 230) {
uint8_t *rightPixel = pixel + (1)*4;
if (rightPixel[0] == 0 && rightPixel[1] == 0 && rightPixel[2] == 0) {
uint8_t *bottomPixel = pixel + (imageData.imageWidth)*4;
if (bottomPixel[0] == 0 && bottomPixel[1] == 0 && bottomPixel[2] == 0) {
struct Position p;p.x=x;p.y=y;
[self addLeftCorner:p top:true];
}
}
}
}
if (y > 0) { //Check for bottom left bar
//Check top right pixel
uint8_t *topRightPixel = pixel + (-imageData.imageWidth + 1)*4;
if (topRightPixel[2] == 40 && topRightPixel[1] == 80 && topRightPixel[0] == 114) {
uint8_t *rightPixel = pixel + (1)*4;
if (rightPixel[0] == 0 && rightPixel[1] == 0 && rightPixel[2] == 0) {
uint8_t *topPixel = pixel - (imageData.imageWidth)*4;
if (topPixel[0] == 0 && topPixel[1] == 0 && topPixel[2] == 0) {
struct Position p;p.x=x;p.y=y;
[self addLeftCorner:p top:false];
}
}
}
}
}
}
}
在运行它时,addLeftCorner永远不会被调用,如果我将其注释掉,我会额外获得10%的CPU使用率。另外,只需调用方法processPixel就可以单独使用25%的CPU使用率。
这是为什么?有没有办法优化它?我想恢复35%的CPU。
答案 0 :(得分:2)
TL; DR - 您将需要调查使用NSObject -methodForSelector:作为避免Objective-C运行时开销的方法。明智地使用它。
-
来自Smalltalk的一些术语对于保持真实情况的心理模型非常有用。我们通常会引用调用方法而不是调用一个函数来识别像Objective-C这样的动态语言每次都会在运行时解析函数地址以响应类型作为信息接收者的对象。
这种动态调度是动态语言多态性的核心。虽然Objective-C运行时达到了几乎超人的长度,使方法调用尽可能高效,但它永远不会像直接函数调用那样高效。
大多数情况下,方法调用效率低下并不重要。人与人之间的相互作用会淹没效率通常很小的效率。但对于像图像处理这样的计算内核,低效率将变得明显。
通过使用NSObject -methodForSelector:,您可以将该方法解析为函数地址一次,然后跳过运行时查找。仔细研究文档。确保您了解SEL是什么以及IMP是什么。将方法作为函数调用需要两个额外的参数, self 和 _cmd 。确保您了解它们是什么以及它们如何被使用。
最重要的是,确保分析绝对证明绕过这样的运行时是必要的。根据您对问题的描述,我并不完全相信您已经确切地知道问题所在。但你是最了解你软件的人。
您将阻止您使用此方法/函数的对象的多态性的可能性,因此它具体设置您的设计的这一方面,而没有动态语言的通常灵活性