[英]Caching streams in Functional Reactive Programming
我有一個完全使用FRP范例編寫的應用程序,由於我創建流的方式,我認為我遇到了性能問題。 它是用Haxe編寫的,但問題不是特定於語言的。
例如,我有此函數,該函數返回一個流,該流在每次為該特定部分更新配置文件時都進行解析,如下所示:
function getConfigSection(section:String) : Stream<Map<String, String>> {
return configFileUpdated()
.then(filterForSectionChanged(section))
.then(readFile)
.then(parseYaml);
}
在反應式編程庫中,我正在使用稱為promhx的鏈的每個步驟都應該記住其最后解析的值,但是我認為每次調用此函數時,我都會重新創建流並重新處理每個步驟。 這是我使用它而不是使用庫的方式的問題。
由於在每次需要YAML時都在解析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;
}
這可能是解決問題的好方法,但我覺得不合適。 我想知道是否有人能想到一個更干凈的解決方案,它可能使用功能更強大的方法(關閉等),甚至可以像緩存功能一樣添加到流中。
我可以做的另一種方法是先創建流,然后將其存儲在消費者可以訪問的字段中。 我不喜歡這種方法,因為我不想為每個配置節創建一個字段,我喜歡能夠調用具有特定節的函數並返回流。
我喜歡任何可以給我帶來新觀點的想法!
好吧,我認為一個答案是像這樣抽象出緩存:
class Test {
static function main() {
var sideeffects = 0;
var cached = memoize(function (x) return x + sideeffects++);
cached(1);
trace(sideeffects);//1
cached(1);
trace(sideeffects);//1
cached(3);
trace(sideeffects);//2
cached(3);
trace(sideeffects);//2
}
@:generic static function memoize<In, Out>(f:In->Out):In->Out {
var m = new Map<In, Out>();
return
function (input:In)
return switch m[input] {
case null: m[input] = f(input);
case output: output;
}
}
}
您也許可以找到一種更“實用”的實現方式來進行memoize
記錄。 但是重要的是,它現在是單獨的東西,您可以隨意使用它。
您可以選擇memoize(parseYaml)
以便在文件中的兩個狀態都被解析一次之后,切換它們的狀態實際上變得非常便宜。 您還可以根據最有價值的策略調整備忘錄以管理緩存大小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.