【问题标题】:F# async ; Run asynch expression in same thread, and yet be able to wait on async operations (e.g. do!)F#异步;在同一个线程中运行异步表达式,但能够等待异步操作(例如,做!)
【发布时间】:2014-07-13 17:00:52
【问题描述】:

用 F# async 进行一些实验告诉我,我可以在 当前正在运行的线程上 StartImmediate。这似乎允许我运行一个异步表达式,它仍然可以传递控制,无论何时进入它内部进行一些异步操作(例如,做!),到异步表达式之外的代码。请看下面的简单示例:

open System.Threading

let workThenWait() = async { 
  printfn "async start"
  do! Async.Sleep(1000) 
  printfn "async end"
  }

let demo() = 
  workThenWait() |> Async.StartImmediate
  printfn "main started"
  // here I want to wait to the async expression in case it has passed control
  printfn "main end"

demo()

我们得到的结果是:

async start
main started
main end
async end

另一方面,如果我使用 StartAsTask(在演示中)执行相同的异步表达式(在本例中为 workThenWait),我可能会在结尾。

我的问题是:

使用前面使用 StartImmediate 的示例,我是否可以在同一个线程上运行,但也可以在结束时等待异步表达式,以防调用某些异步操作(例如 do!)并向前传递控制权?

【问题讨论】:

    标签: f# f#-async


    【解决方案1】:

    我认为你需要Async.RunSynchronously (http://msdn.microsoft.com/en-us/library/ee370262.aspx)

    更新: 好的,现在我更好地理解了你想要什么,我能够通过Async.StartWithContinuations 方法实现这一点。

    代码如下:

    open System.Threading
    let f() =
    printfn "main thread: %A" Thread.CurrentThread.ManagedThreadId
    let c1 = 
        async {
                printfn "c1 async thread: %A" Thread.CurrentThread.ManagedThreadId
                do! Async.Sleep(1000) 
                return "some result"
              }
    
    let continuation s = 
        printfn "continuation thread: %A" Thread.CurrentThread.ManagedThreadId
        printfn "now the code You want after waiting and the result %s" s
    
    Async.StartWithContinuations( 
        c1, 
        continuation,
        (fun _ -> ()), 
        (fun _ -> ())
        )
    
    printfn "Code that runs during async computation"
    

    现在这绝对不是很可读,因为代码的流程并不明显。我找不到更好的解决方案。

    【讨论】:

    • RunSynchronously 的工作方式与 StartImmediate 不同,因为它将阻止异步操作(例如 do!)来转发控制。我的查询是这样的场景:在执行异步操作(例如 do! ==> 将控制权转发到异步表达式之外的代码 ==> 但是,这是我的问题,最后仍然可以等待异步表达式
    • 感谢您的澄清,我已经更新了答案。
    • 这很有用。我知道 StartWithContinuations 但没有意识到它可能是唯一可行的方法。我会再等一会儿,看看是否有一些 guru f# 编码员能想出一个更清晰、更易读的版本,然后关闭线程。谢谢 Grzegorz Sławecki。
    • 谢谢!我也很好奇这是否可以以更易读的方式完成。
    【解决方案2】:

    您可以使用 Hopac 库:

    let workThenWait() = job { 
      printfn "async start"
      do! Hopac.Timer.Global.sleep (TimeSpan.FromMilliseconds 1000.) 
      printfn "async end"
      }
    
    let demo() = 
      let promise = workThenWait() |> Promise.start |> run
      printfn "main started"
      // here I want to wait to the async expression in case it has passed control
      let result = run promise
      printfn "main end"
    
    demo()
    

    Hopac 的性能和功能都比 async 更高,与它的性能相比鲜为人知。我强烈推荐它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2014-10-02
      • 2015-05-22
      • 1970-01-01
      • 2021-09-05
      相关资源
      最近更新 更多