如何优化F#代码中嵌套的async异步块冗余结构?
F# 交易所K线拉取代码优化方案
核心优化点
- 移除冗余异步嵌套:删除不必要的
downloadedCandles内层async块,直接把拉取逻辑合并到主异步流程;递归拉取函数提取到主函数外部,避免多层嵌套。 - 优化列表拼接性能:原递归中每次用
@拼接列表的操作在数据量较大时性能损耗严重,改为从头部追加元素,递归结束后统一反转,时间复杂度从O(n²)降到O(n)。 - 简化分支判断:简化缓存时间计算、是否需要拉取新数据的判断逻辑,减少冗余中间变量。
优化后代码
// 递归拉取函数提取到外层,避免嵌套在主async块中 let rec private getMissingCandlesAsync (exchange: IExchange) (instrument: Instrument) (interval: TimeSpan) (acc: CandleData list) (fromTime: DateTime) (toTime: DateTime) = async { let! candles = exchange.GetCandlesAsync(instrument, interval, fromTime, toTime) if candles.IsError then return failwith candles.GetError.Describe let newCandles = candles.Get // 头部追加代替列表拼接,减少性能损耗 let newAcc = List.append newCandles acc let lastReceivedTime = newCandles.[^0].Timestamp if lastReceivedTime < toTime - interval then return! getMissingCandlesAsync exchange instrument interval newAcc (lastReceivedTime + interval) toTime else // 统一反转得到正序数据 return List.rev newAcc } let getCandlesFromAsync (exchange: IExchange) (instrument: Instrument) (interval: TimeSpan) (fromTime: DateTime) (toTime: DateTime) = async { // 读取本地缓存 let cache = DataCache.getCache instrument let cachedCandles = getCandlesFromCache cache interval fromTime toTime // 计算缺失数据的起始时间 let firstMissingTime = if cachedCandles.IsEmpty then fromTime else cachedCandles.[^0].Timestamp + interval // 直接判断是否需要拉取新数据,删除冗余async块 if firstMissingTime >= toTime then return cachedCandles else let! newCandles = getMissingCandlesAsync exchange instrument interval [] firstMissingTime toTime putCandlesInCache cache newCandles return List.append cachedCandles newCandles }
可选优化建议
如果不需要强制抛出异常,可把错误处理改为返回Result<CandleData list, string>类型,更符合F#函数式编程的错误处理习惯,避免上层调用未捕获异常导致程序崩溃。如果拉取的K线数据量特别大,还可以考虑把列表换成ResizeArray(即C#的List)来缓存中间结果,性能会更好。
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

