[英]antlr4 performance on a multiple-core CPU
最近,我的程序遇到了性能问题。 调查最终指出了我用来解析 SQL 的 antlr4 深处的一个问题。 如代码所示,dfa.states 上有一个同步块。 该块实际上限制了具有 8 个或更多内核的计算机上的解析性能。 我想知道是否有人遇到过这个问题并找到了解决方案?
protected DFAState addDFAState(ATNConfigSet configs) {
/* the lexer evaluates predicates on-the-fly; by this point configs
* should not contain any configurations with unevaluated predicates.
*/
assert !configs.hasSemanticContext;
DFAState proposed = new DFAState(configs);
ATNConfig firstConfigWithRuleStopState = null;
for (ATNConfig c : configs) {
if ( c.state instanceof RuleStopState ) {
firstConfigWithRuleStopState = c;
break;
}
}
if ( firstConfigWithRuleStopState!=null ) {
proposed.isAcceptState = true;
proposed.lexerActionExecutor = ((LexerATNConfig)firstConfigWithRuleStopState).getLexerActionExecutor();
proposed.prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex];
}
DFA dfa = decisionToDFA[mode];
synchronized (dfa.states) {
DFAState existing = dfa.states.get(proposed);
if ( existing!=null ) return existing;
DFAState newState = proposed;
newState.stateNumber = dfa.states.size();
configs.setReadonly(true);
newState.configs = configs;
dfa.states.put(newState, newState);
return newState;
}
}
经过几天的挣扎,我能够找到解决方案。 正如 Mike Lische 所说,同步块似乎试图减少内存占用。 但它对具有繁重 SQL 解析工作负载的多核计算机的性能有显着影响。 我试图解析由 mysqldump 生成的 100gb+ SQL 文件。
我的解决方案是使用克隆的 DFA 而不是静态解释器创建自定义解释器。 结果在我的 16 核 AMD threadripper 上几乎好 10 倍,CPU 使用率超过 95%。
setInterpreter(new LexerATNSimulator(this, _ATN, getDFA(), new PredictionContextCache()));
private DFA[] getDFA() {
DFA[] result = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
result[i] = new DFA(_ATN.getDecisionState(i), i);
}
return result;
}
出于内存效率的原因,给定语言的所有解析器实例共享相同的 DFA(它是一个静态结构)。 然而,这需要使这个结构线程安全(解析器可以在后台线程中使用)。 没办法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.