Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asynchronous 可以无限异步工作流溢出堆栈吗_Asynchronous_F# - Fatal编程技术网

Asynchronous 可以无限异步工作流溢出堆栈吗

Asynchronous 可以无限异步工作流溢出堆栈吗,asynchronous,f#,Asynchronous,F#,假设我们有一个潜在的无休止的工作流: let workAsync i = async { printfn "Working... %A" i if i > 3 then failwith "errg" elif i = -1000 then // ensure work is async do! Async.Sleep 0 return i+1 } let workflow = async { le

假设我们有一个潜在的无休止的工作流:

let workAsync i = async { 
    printfn "Working... %A" i
    if i > 3 then
        failwith "errg"
    elif i = -1000 then // ensure work is async
        do! Async.Sleep 0
    return i+1
}

let workflow =
    async {
        let mutable i = 0
        while true do           // I can't quit you!
            let! j = workAsync i
            i <- j
            //do! Async.Sleep 0 // This is important?
    } |> Async.RunSynchronously
让workAsync i=async{
printfn“工作…%A”i
如果我大于3,那么
用“错误”表示失败
如果i=-1000,则//确保工作是异步的
执行!异步。睡眠0
返回i+1
}
让工作流=
异步的{
设可变i=0
尽管如此,我还是不能离开你!
设!j=workAsync i
我异步运行
如果运行此命令,我们将得到预期的异常。请注意stacktrace是如何增长的。此命令可以放大

Working... 0
Working... 1
Working... 2
Working... 3
Working... 4
> System.Exception: errg
  at FSI_0017.workAsync@155-45.Invoke(Unit unitVar) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 157
  at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2)
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at FSI_0017.workAsync@158-47.Invoke(AsyncActivation`1 ctxt) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 158
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at FSI_0017.workAsync@158-47.Invoke(AsyncActivation`1 ctxt) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 158
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at FSI_0017.workAsync@158-47.Invoke(AsyncActivation`1 ctxt) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 158
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at FSI_0017.workAsync@158-47.Invoke(AsyncActivation`1 ctxt) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 158
  at Microsoft.FSharp.Control.AsyncPrimitives.unitAsync@607.Invoke(AsyncActivation`1 ctxt)
  at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction)
--- End of stack trace from previous location where exception was thrown ---
  at Microsoft.FSharp.Control.AsyncResult`1.Commit()
  at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInAnotherThread[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
  at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout)
  at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
  at <StartupCode$FSI_0017>.$FSI_0017.main@() in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 161
正在工作…0
工作…1
工作……2
工作……3
工作……4
>系统异常:errg
在FSI0017。workAsync@155-45.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(Unit unitVar):第157行
在Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](异步激活'1 ctxt,TResult result1,FSharpFunc'2 part2)
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
在FSI0017。workAsync@158-47.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(AsyncActivation`1 ctxt):第158行
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
在FSI0017。workAsync@158-47.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(AsyncActivation`1 ctxt):第158行
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
在FSI0017。workAsync@158-47.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(AsyncActivation`1 ctxt):第158行
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
在FSI0017。workAsync@158-47.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(AsyncActivation`1 ctxt):第158行
位于Microsoft.FSharp.Control.AsyncPrimitives。unitAsync@607.Invoke(异步激活'1 ctxt)
在Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction)上
---来自引发异常的上一个位置的堆栈结束跟踪---
在Microsoft.FSharp.Control.AsyncResult`1.Commit()中
在Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronousLyinOtherThread[a](CancellationToken令牌,FSharpAsync`1计算,FSharpOption`1超时)
在Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken CancellationToken,FSharpAsync`1计算,FSharpOption`1超时)
在Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1计算,FSharpOption`1超时,FSharpOption`1取消令牌)
位于C:\work\website\u tq\tqit7\fs\Scripts\FSI_basic.fsx中的.FSI_0017.main@():第161行
但是如果我们取消对Async.Sleep行的注释,堆栈不会增长:

Working... 0
Working... 1
Working... 2
Working... 3
Working... 4
> System.Exception: errg
   at FSI_0002.workAsync@155.Invoke(Unit unitVar) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 157
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2)
   at FSI_0002.workflow@167-5.Invoke(AsyncActivation`1 ctxt) in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 167
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.FSharp.Control.AsyncResult`1.Commit()
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInAnotherThread[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout)
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
   at <StartupCode$FSI_0002>.$FSI_0002.main@() in C:\work\website_tq\tqit7\fs\Scripts\fsi_basic.fsx:line 161
正在工作…0
工作…1
工作……2
工作……3
工作……4
>系统异常:errg
在FSI_0002。workAsync@155.InvokeC:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中的(Unit unitVar):第157行
在Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](异步激活'1 ctxt,TResult result1,FSharpFunc'2 part2)
在FSI_0002。workflow@167-5.在C:\work\website\u tq\tqit7\fs\Scripts\fsi\u basic.fsx中调用(AsyncActivation`1 ctxt):第167行
在Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction)上
---来自引发异常的上一个位置的堆栈结束跟踪---
在Microsoft.FSharp.Control.AsyncResult`1.Commit()中
在Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronousLyinOtherThread[a](CancellationToken令牌,FSharpAsync`1计算,FSharpOption`1超时)
在Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken CancellationToken,FSharpAsync`1计算,FSharpOption`1超时)
在Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1计算,FSharpOption`1超时,FSharpOption`1取消令牌)
在C:\work\website\u tq\tqit7\fs\Scripts\FSI_basic.fsx中的.FSI_0002.main@()处:第161行

*修改:更改了
workAsync
,以确保不优化异步性。

发生这种情况是因为在注释掉
睡眠
时,工作流中实际上没有任何异步

所有内容都是完全同步的,但因为它是在
async
计算表达式中编码的,所以它的嵌套方式很奇怪。请看,每一行
let!
实际上都调用右侧的内容(在您的示例中-
workAsync
)并将异步部分完成后需要调用的回调传递给它。回调包含代码的其余部分-一个从
let!
行之后开始的延续。编译器对代码执行巧妙的转换,使其看起来非常漂亮和线性,而实际上它是一系列回调

但是,由于
workAsync
实际上并不是异步的,所以它只会立即调用回调,而回调会反过来调用
workAsync
的下一次迭代,依此类推。因此堆栈会增长

但是等等!它实际上不应该增长。回调调用是
workAsync
中的最后一个调用,也称为“tail call”;.NETCore和.NET Framework都会消除它们(事实上:在我的机器上,我无法复制您的结果)我唯一能提供的猜测是你一定是在Mono上运行这个,Mono并不总是排除尾部调用

但是,如果取消注释
Sleep
,则它将成为断点。
Sleep
实际上是异步的,这意味着它将在超时后在新线程上执行回调。该执行从零开始,使用新堆栈,因此stac