F# STA 线程异步

lib*_*tor 5 .net f# multithreading asynchronous

我在 GUI 线程中将此函数称为:

let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
    async {
      while target.Continue do
        let context = System.Threading.SynchronizationContext.Current
        do! Async.SwitchToThreadPool()
        System.Threading.Thread.Sleep(10000)
        do! Async.SwitchToContext(context)
        let image = target.CreateImage()
        match image with
        | Some userImage -> do! target.UpdateImageView userImage 
        | None -> ()
    } |> Async.StartImmediate
Run Code Online (Sandbox Code Playgroud)

问题出现在执行target.UpdateImageView方法时,产生异常:

调用线程必须是 STA,因为许多 UI 组件都需要它。

我知道,但这就是我所做的

do! Async.SwitchToContext(context)
Run Code Online (Sandbox Code Playgroud)

消除 SwitchToContext 和 SwitchToThreadPool 函数可以消除异常,但 GUI 只是冻结。这是有道理的,但为什么我不能在线程之间切换?

产生问题的函数是UpdateImageView。我在异步和不异步的情况下测试了它。

member this.UpdateImageView  etoimage =
  async {
    let imageview = new Eto.Forms.ImageView()
    imageview.Image <- etoimage
    this.Content <- imageview
  }
Run Code Online (Sandbox Code Playgroud)

编辑 - -

Testing with this code:
let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
    let context = System.Threading.SynchronizationContext.Current
    let printThread text =
        printfn "[%d] %s" System.Threading.Thread.CurrentThread.ManagedThreadId text
    async {
      while target.Continue do
        printThread "begining"
        do! Async.SwitchToThreadPool()
        printThread "after swith to thread pool"
        let image = target.CreateImage()
        match image with
        | Some userImage -> 
            printThread "before switch to context"
            do! Async.SwitchToContext context 
            printThread "after switch to context"
            target.UpdateImageView userImage 
        | None -> ()
    } |> Async.StartImmediate
Run Code Online (Sandbox Code Playgroud)

印刷 :

[1] begining 
[4] after swith to thread pool 
[4] before switch to context 
[5] after switch to context
Run Code Online (Sandbox Code Playgroud)

Fun*_*l_S 4

  1. 使用 [< STAThread >]

  2. 使用 guiContext 在 GUI 上工作

在你的 GUI 创建(框架初始化)中记住 guiContext

let guiContext = System.Threading.SynchronizationContext.Current 
Run Code Online (Sandbox Code Playgroud)

并将其传递给异步 GUI 执行

// the async GUI execute 
async {
            let currentContext = System.Threading.SynchronizationContext.Current 
            do! Async.SwitchToContext(guiContext)
            f() // work on the GUI
            do! Async.SwitchToContext(currentContext)   
}
Run Code Online (Sandbox Code Playgroud)

将等待放在一个额外的步骤中以保持其可组合性。