我在Objective-c中实现了几乎相同的代码,运行速度比Java快两到三倍。我正在试图找出哪些指令可能是最耗费资源的,并且看看是否有更好的方法来做同样的事情,这在Java中更有效。
这是从数据库中读取大型结果集的例程的一部分,对于返回的每个单词,它会检查该单词是否可以由玩家具有的字母区块构成。它包括对空白图块的支持,可以用作任何字母。空白图块将以下划线字符表示。
基本上,对于从数据库返回的每个单词,我遍历单词的每个字母,并查看可用字母的玩家数组。如果我找到那封信,我将其从玩家阵列中移除并继续前进。如果我没有找到该字母,则该字被丢弃并且下一个字被读取。除非,我在播放器的数组中找到一个下划线字符,然后,我将使用它作为字母,并将其从数组中删除。如果我到达数据库字的字母数组的末尾并且每个字母都“找到”,那么该单词将保存在列表中。
我已经计时整个函数的各个部分,数据库查询发生得非常快。这只是对这个游标的处理非常慢。任何建议将不胜感激!
if (c.moveToFirst()) {
do {
boolean found = false;
int aValue = 0;
int letterValue = 0;
// Word and Word's length from the database
String sWord = c.getString(0);
int wordLength = c.getInt(1);
// Refresh the Tile array, underscores sorted to the front
// sortedTiles sorted the players tiles {_,_,a,b,c}
char[] aTiles = sortedTiles.clone();
// Calculate the value of the word
for (int i = 0; i < wordLength; i++) {
// For each character in the database word
switch (sWord.charAt(i)) {
case 97:
letterValue = 1;
break;
case 98:
letterValue = 4;
break;
case 99:
letterValue = 4;
break;
case 100:
letterValue = 2;
break;
case 101:
letterValue = 1;
break;
case 102:
letterValue = 4;
break;
case 103:
letterValue = 3;
break;
case 104:
letterValue = 3;
break;
case 105:
letterValue = 1;
break;
case 106:
letterValue = 10;
break;
case 107:
letterValue = 5;
break;
case 108:
letterValue = 2;
break;
case 109:
letterValue = 4;
break;
case 110:
letterValue = 2;
break;
case 111:
letterValue = 1;
break;
case 112:
letterValue = 4;
break;
case 113:
letterValue = 10;
break;
case 114:
letterValue = 1;
break;
case 115:
letterValue = 1;
break;
case 116:
letterValue = 1;
break;
case 117:
letterValue = 2;
break;
case 118:
letterValue = 5;
break;
case 119:
letterValue = 4;
break;
case 120:
letterValue = 8;
break;
case 121:
letterValue = 3;
break;
case 122:
letterValue = 10;
break;
default:
letterValue = 0;
break;
} // switch
found = false;
// Underscores will be sorted to the front of the array,
// so start from the back so that we give
// real letters the first chance to be removed.
for (int j = aTiles.length - 1; j > -1; j--) {
if (aTiles[j] == sWord.charAt(i)) {
found = true;
// Increment the value of the word
aValue += letterValue;
// Blank out the player's tile so it is not reused
aTiles[j] = " ".charAt(0);
// I was removing the element from the array
// but I thought that might add overhead, so
// I switched to just blanking that letter out
// so that it wont be used again
//aTiles = removeItem(aTiles, j);
break;
}
if (aTiles[j] == cUnderscore) {
found = true;
// Blank out the player's tile so it is not reused
aTiles[j] = " ".charAt(0);
// I was removing the element from the array
// but I thought that might add overhead, so
// I switched to just blanking that letter out
// so that it wont be used again
//aTiles = removeItem(aTiles, j);
break;
}
} // for j
// If a letter in the word could not be fill by a tile
// or underscore, the word doesn't qualify
if (found == false) {
break;
}
} // for i
// If all the words letters were found, save the value and add to the list.
if (found == true) {
// if all the tiles were used it's worth extra points
String temp = aTiles.toString().trim();
if (temp.length() < 1) {
aValue += 35;
}
Word word = new Word();
word.word = sWord;
word.length = wordLength;
word.value = aValue;
listOfWords.add(word);
}
} while (c.moveToNext());
}
答案 0 :(得分:8)
我不知道您的代码在大部分时间内的确切位置。你应该描述一下。但我会用表查找替换你的long switch语句:
// In the class:
private static final int[] letterValues = {
1, 4, 4, 2, 1, // etc.
}
// In the code:
// Calculate the value of the word
for (int i = 0; i < wordLength; i++) {
// For each character in the database word
char ch = sWord.charAt(i);
if (ch >= 97 && ch <= 122) {
letterValue = letterValues[ch - 97];
} else {
letterValue = 0;
}
// the rest of your code
这可能比switch语句快得多。
编辑:我注意到,在j
循环中,您为每个sWord.charAt(i)
值调用了j
。通过将函数调用分解出循环,可以加快速度。如果您使用我的代码,则可以使用ch
代替sWord.charAt(i)
。
P.S。作为一种风格问题,编码if (found) { ...
代替if (found == true) { ...
更好。同样,请使用if (!found) {
代替if (found == false) {
。
答案 1 :(得分:1)
我认为switch语句可能会被编译器变成跳转表,所以我没有看到它的问题。
另一方面,您可以为玩家的手使用更好的数据结构。现在,你基本上使用了一个三重嵌套循环:
前两个是无法避免的。另一方面,您可以为第三个使用哈希表或某种O(N)查找数据结构。
我可能会将手牌表示为27个整数的数组。每个元素代表一个字母或“_”,其值是手中的瓦片数。找到匹配的图块时,可以减小其值。如果该值已经为零,那么您就知道该播放器没有该磁贴。
但正如泰德指出的那样,最好的办法是使用分析器找到最昂贵的电话。然后弄清楚如何尽可能少地进行这些调用。
答案 2 :(得分:1)
你倾向于得到猜测的答案。
要做的是,在每个平台上,只需squeeze the code until it's optimal。 然后,如果有任何速度差异,至少你会知道每个代码都尽可能快。
分析是经常推荐的,但是here's an example of how I do it。
答案 3 :(得分:0)
谢谢大家。我当时希望得到电子邮件提醒,所以,我没有意识到人们已经在回复。
我最终在光标循环的不同位置放置系统时间的日志打印输出,以尝试确定花费最多时间的内容。最初的moveToFirst()占用了大部分时间,但这是可以预料的,我真的无能为力。我注意到大多数单词在两三毫秒内处理,这应该足够快,但是,由于没有明显的原因,一个单词需要20或30毫秒。我推断在后台必须进行一些垃圾收集,因此,我试图尽可能地减少分配/解除分配。在所有的循环中,而不是声明变量,如(int i = 0 ... to for(i = 0,将变量声明移动到方法的顶部。这有点帮助,但我仍然离开一条线未触及。当我改变它时,它在世界上造就了一切。
// Refresh the Tile array, underscores sorted to the front
for (i = 0; i < sortedTiles.length; i++) {
aTiles[i] = sortedTiles[i];
}
// Instead of doing it this way
//aTiles = sortedTiles.clone();
我在游标循环上方分配了一个Tile,在这里,我只是用玩家手中的角色重新初始化它。这一个clone()是必要的频繁垃圾收集,并且杀死了我的表现。
您已经提供了很好的建议,我会进一步调整代码,根据您的建议提高效果。非常感谢你!