我在开发Web服务器上运行以下递归函数时遇到问题。它会导致堆栈溢出。在调试模式下,它在本地运行良好。以下是我尝试过的事情:
所以我的问题是:
谢谢!
let rec SimulationLoop (rowNum : int) (h : double) (time : double) (v : double) (s : double) (p : double) (newV' : double) (newS' : double) (newP' : double) (designParameters : DesignParameters) (inputs : ISimulationInputProvider) = seq {
//let timer = System.Diagnostics.Stopwatch.StartNew()
let finalTime = (6.0 * inputs.ShockAbsorber.Stroke / designParameters.VelocityAfterImpact)
let startH = StartH h time finalTime
let slopes = Slopes v s p newV' newS' newP' startH designParameters inputs
let vSlope, sSlope, pSlope = slopes
let betaList = [ for j in 0 .. 5 -> beta.[j].[4] ]
let newV' = CalcPrime v startH vSlope betaList
let newS' = CalcPrime s startH sSlope betaList
let newP' = CalcPrime p startH pSlope betaList
let delta = Delta h slopes
let tau = Tau v s p
let rowResult, rowNum, time, newV, newS, newP = if delta < tau then RecordResults rowNum time startH v s p slopes designParameters inputs else None, (rowNum + 1), time, v, s, p
let loop = newS < inputs.ShockAbsorber.Stroke - 0.01 && newV >= 0.0 && rowNum <= 8000 && (time < finalTime && time + h > time)
let stepLength = StrokeStepLength inputs.ShockAbsorber.Stroke designParameters.HoleSize
let endH = EndH delta startH tau stepLength newV
//timer.Stop()
//System.Diagnostics.Debug.WriteLine("Row: " + rowNum.ToString() + " = " + timer.ElapsedMilliseconds.ToString())
match (rowResult, loop) with
| Row(r), true ->
yield r
yield! SimulationLoop rowNum endH time newV newS newP newV' newS' newP' designParameters inputs
| Row(r), false ->
yield r
| None, true ->
yield! SimulationLoop rowNum endH time newV newS newP newV' newS' newP' designParameters inputs
| None, false -> ()
}
答案 0 :(得分:1)
因为函数体是序列表达式,所以编译器不使用尾递归。但是,仅调用SimulationLoop
绝对不会导致堆栈溢出,因为它应该只生成序列而不评估其内容。此外,鉴于代码的性质,我希望编译器生成的状态机可以逐步运行序列而不会溢出堆栈。
当您看到错误时,如何使用调用SimulationLoop
的结果?本地和Web机器的平台是什么(例如它们都是32位)?如果您减少了示例(例如,删除了对CalcPrime
,RecordResults
等的调用),您会看到相同的行为吗?
答案 1 :(得分:0)
我最终在没有递归的情况下重写它。这不是最优雅的解决方案,但它有效:
let SimulationLoop (rowNum : int) (h : double) (time : double) (v : double) (s : double) (p : double) (newV' : double) (newS' : double) (newP' : double) (designParameters : DesignParameters) (inputs : ISimulationInputProvider) =
let mutable mKeepLooping = true
let mutable mRowNum = 1
let mutable mEndH = h
let mutable mTime = time
let mutable mNewV = v
let mutable mNewS = s
let mutable mNewP = p
let mutable mNewV' = newV'
let mutable mNewS' = newS'
let mutable mNewP' = newP'
let theList = new List<SimulationRow>()
while mKeepLooping do
let finalTime = (6.0 * inputs.ShockAbsorber.Stroke / designParameters.VelocityAfterImpact)
let startH = StartH mEndH mTime finalTime
let slopes = Slopes mNewV mNewS mNewP mNewV' mNewS' mNewP' startH designParameters inputs
let vSlope, sSlope, pSlope = slopes
let betaList = [ for j in 0 .. 5 -> beta.[j].[4] ]
let mNewV' = CalcPrime v startH vSlope betaList
let mNewS' = CalcPrime s startH sSlope betaList
let mNewP' = CalcPrime p startH pSlope betaList
let delta = Delta mEndH slopes
let tau = Tau mNewV mNewS mNewP
let rowResult, rowNum, time, newV, newS, newP = if delta < tau then RecordResults mRowNum mTime startH mNewV mNewS mNewP slopes designParameters inputs else None, (mRowNum + 1), mTime, mNewV, mNewS, mNewP
mRowNum <- rowNum
mTime <- time
mNewV <- newV
mNewS <- newS
mNewP <- newP
let loop = newS < inputs.ShockAbsorber.Stroke - 0.01 && newV >= 0.0 && rowNum <= 8000 && (time < finalTime && time + h > time)
mKeepLooping <- loop
let stepLength = StrokeStepLength inputs.ShockAbsorber.Stroke designParameters.HoleSize
mEndH <- EndH delta startH tau stepLength newV
match rowResult with
| Row(r) ->
theList.Add(r)
| _ -> ()
theList