簡體   English   中英

如何將條件鏈轉換為速度更快,更丑陋的代碼?

[英]How do I turn a conditional chain into faster less ugly code?

我有9種不同的語法。 其中一個將根據要解析的文件上txt的第一行加載。

我正在考慮將詞法分析器/解析器生成為sep。 類,然后在我獲得比賽后立即實例化它們-不知道這是否會使我慢下來。 我想應該進行一些基准測試。

確實, 速度絕對是我在這里的目標,但是我知道這是丑陋的代碼。

現在,代碼看起來像這樣:

sin.mark(0)
site = findsite(txt)
sin.reset()

if ( site == "site1") {
   loadlexer1;
   loadparser1;
} else if (site == "site2") {
   loadlexer2;
   loadparser2;
}
.................
} else if (site == "site8") {
   loadparser8;
   loadparser8;
}

findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") {
    site = site1;
  } else if(line.indexOf("site2-identifier") {
    site = site2;
  } else if(line.indexOf("site3-identifier") {
    site = site3;
  }
  .........................
  } else if(line.indexOf("site8-identifier") {
    site = site8;
  }
}

一些澄清

1)是的,我確實有9個使用antlr構建的不同語法,因此它們都將具有自己的詞法分析器/解析器objs。

2)是的,截至目前,我們正在比較字符串,並且很明顯,它將被某種整數映射代替。 我還考慮過將站點標識符粘貼到一個正則表達式中,但是我認為這不會加快任何速度。

3)是的,這是偽代碼,因此在這里我不會太挑剔。

4)kdgregory是正確的,因為我無法創建一個詞法分析器/解析器對的實例

我喜歡散列的想法,使代碼看起來更好一點,但是我認為這不會加快我的速度

標准方法是使用Map將密鑰字符串連接到將處理它們的詞法分析器:

Map<String,Lexer> lexerMap = new HashMap<String,Lexer>();
lexerMap.put("source1", new Lexer01());
lexerMap.put("source2", new Lexer02());
// and so on

一旦檢索到標識要使用的詞法分析器的字符串,就可以從Map中檢索它,如下所示:

String grammarId = // read it from a file, whatever
Lexer myLexer = lexerMap.get(grammarId);

但是,您的示例代碼有一些怪癖。 首先,indexOf()調用指示您沒有獨立的字符串,並且Map不會在字符串內部查找。 因此,您需要某種方法從讀取的任何字符串中提取實際密鑰。

其次,詞法分析器和解析器通常維護狀態,因此您將無法創建單個實例並重用它。 這表明您需要創建一個工廠類,並將其存儲在地圖中(這是“抽象工廠”模式)。

如果您期望有很多不同的詞法分析器/解析器,則使用映射驅動的方法是有意義的。 對於較小的數字,if-else鏈可能是最好的選擇,並進行適當封裝(這是Factory Method模式)。

幾乎可以肯定,使用多態比字符串操作要快,並且在編譯時會檢查其正確性。 site真的是字符串嗎? 如果是這樣,則FindSite應該稱為GetSiteName。 我希望FindSite返回一個知道適當的詞法分析器和解析器的Site對象。

另一個速度問題是編碼速度。 在單個類中擁有不同的詞法分析器和解析器肯定會更好(也許在另一個類中具有共享功能)。 這將使您的代碼略小一些,並且使他人易於理解。

就像是:

Map<String,LexerParserTuple> lptmap = new HashMap<String,LexerParserTuple>();
lpt=lptmap.get(site)
lpt.loadlexer()
lpt.loadparser()

結合一些正則表達式魔術而不是string.indexOf()來獲取站點名稱,應該可以極大地清理代碼。

用多態替換條件

對於一半來說,對於findsite(),您可以簡單地設置一個HashMap以使您從站點標識符到站點。 另一種清除方式是簡單地返回站點字符串,因此:

String findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") 
    return site1;
  if(line.indexOf("site2-identifier")
    return  site2;
  if(line.indexOf("site3-identifier")
    return  site3;
...
}

以這種方式使用indexOf()並不真正具有表達力; 我會使用equals()或contains()。

我正在考慮將詞法分析器/解析器生成為sep。 類,然后在我找到匹配項后實例化它們

看來您已經有了答案。 這將創建更靈活的代碼,但不一定更快。

我想應該進行一些基准測試

是的,用兩種方法進行測量並做出明智的決定。 我的猜測是您擁有它的方式已經足夠。

也許,如果麻煩的是使用“公里數”方法,則可以使用extract方法將其重構為不同的函數。

最重要的是,首先要有一個解決方案,即使它運行緩慢,也能完成任務;一旦工作,就對其進行概要分析,並找出可以提高性能的點。 記住“優化規則”

假設您的代碼效率低下。

實際解析輸入是否需要比(例如)1%的時間更多的時間?

如果沒有,您將擁有更大的“炸魚”。

我會更改find​​site的類型以返回站點類型(超類),然后利用多態性...這應該比字符串操作要快...

您需要單獨的詞法分析器嗎?

使用地圖將站點配置為加載策略結構。 然后,需要基於“站點”進行簡單查找,然后執行適當的策略。 可以對findSite()執行相同的操作。

可以有一個標識符與站點的映射,然后僅對映射條目進行迭代。

// define this as a static somewhere ... build from a properties file
Map<String,String> m = new HashMap<String,String>(){{
    put("site1-identifier","site2");
    put("site2-identifier","site2");
}}

// in your method
for(Map.Entry<String,String> entry : m.entries()){
    if( line.contains(entry.getKey())){
        return line.getValue();
    }
}

清潔工:是的,更快:不知道...應該足夠快

您可以使用反射

char site = line.charAt(4);
Method lexerMethod = this.getClass().getMethod( "loadLexer" + site, *parameters types here*)
Method parserMethod = this.getClass().getMethod( "loadparser" + site, *parameters types here*)

lexerMethod.invoke(this, *parameters here*);
parserMethod.invoke(this, *parameters here*);

我不了解Java,但是有些語言允許switch接受字符串。

switch(site)
{
    case "site1": loadlexer1; loadparser1; break;
    case "site2": loadlexer2; loadparser2; break;
    ...
}

至於秒位,請使用正則表達式提取標識符並打開。 使用enum可能會更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM