我有一个完全使用FRP范例编写的应用程序,我认为由于我创建流的方式,我遇到了性能问题。它是用Haxe编写的,但问题不是语言特定的。
例如,我有这个函数返回一个流,该流在每次为特定部分更新配置文件时解析,如下所示:
function getConfigSection(section:String) : Stream<Map<String, String>> {
return configFileUpdated()
.then(filterForSectionChanged(section))
.then(readFile)
.then(parseYaml);
}
在我使用的反应式编程库promhx中,链的每一步都应该记住它的最后一个解析值,但我想每次调用这个函数时我都会重新创建流并重新处理每一步。这是我使用它而不是库的方式的问题。
由于在每次需要时解析YAML的所有地方都会调用此函数,这会导致性能下降,并且根据性能分析占用CPU时间的50%以上。
作为修复,我使用存储为缓存流的实例变量的Map执行了类似下面的操作:
function getConfigSection(section:String) : Stream<Map<String, String>> {
var cachedStream = this._streamCache.get(section);
if (cachedStream != null) {
return cachedStream;
}
var stream = configFileUpdated()
.filter(sectionFilter(section))
.then(readFile)
.then(parseYaml);
this._streamCache.set(section, stream);
return stream;
}
这可能是解决问题的一个很好的解决方案,但它对我来说并不合适。我想知道是否有人可以想到一个更干净的解决方案,可能使用更多功能的方法(闭包等),甚至是我可以添加到流中的扩展,如缓存功能。
我能做到的另一种方法是先预先创建流,然后将它们存储在消费者可以访问的字段中。我不喜欢这种方法,因为我不想为每个配置部分创建一个字段,我喜欢能够调用具有特定部分的函数并返回流。
我喜欢任何可以给我一个全新视角的想法!
答案 0 :(得分:2)
嗯,我想一个答案就是抽象出缓存like so:
memoize
您可能会为memoize(parseYaml)
找到更具“功能性”的实施方案。但重要的是它现在是一个单独的东西,你可以随意使用它。
您可以选择{{1}},以便在解析文件后,切换文件中的两个状态实际上变得非常便宜。您还可以根据任何证明最有价值的策略来调整memoize以管理缓存大小。