Вопрос

I have a COM object, which I connect to, and I should recieve an event, which would confirm that connection is established. I write code and test it in F# interactive, and for some reason it wouldn't catch COM events when I use Async.RunSynchronously.

/// This class wraps COM event into F# Async-compatible event
type EikonWatcher(eikon : EikonDesktopDataAPI) =
    let changed = new Event<_>()
    do eikon.add_OnStatusChanged (fun e -> changed.Trigger true)
    member self.StatusChanged = changed.Publish

/// My method
let ``will that connection work?`` () = 
    let eikon = EikonDesktopDataAPIClass() :> EikonDesktopDataAPI // create COM object
    let a = async {
        let watcher = EikonWatcher eikon // wrap it 
        eikon.Initialize() |> ignore     // send connection request
        let! result =  Async.AwaitEvent watcher.StatusChanged // waiting event
        printfn "%A" result              // printing result
        return result
    }

    // I use either first or second line of code, not both of them
    Async.Start (Async.Ignore a)            // does not hang, result prints 
    Async.RunSynchronously (Async.Ignore) a // hangs!!!


/// Running
``will that connection work?`` ()

At the same time, code works perfectly well with RunSynchronously when I insert it into console app. What should I do so that to prevent that nasty behavior?

Нет правильного решения

Другие советы

The code we write under within a single Thread (as in STA) feels like it is made of independant pieces each having their own life, but this is actually a fallacy : everything is mediated under a common event loop, which "linearizes" the various calls.

So everything we do, unless explicitely spoecified otherwise, is essentially single threaded and you can not wait for yourself without creating a deadlock.

When you specify Async.Start it does start a new, independant computation which runs on its own, a "thread".

Whereas When you call runsynchronously, it awaits on the same 'thread'.

Now if the event you are waiting, which feels like an independant thing, is actually 'linearized' by the same event loop, you are actually waiting for yourself, hence the deadlock.


Something useful if you want to wait "asynchronously", (aka wait for an event, but not actually block and leave the opportunity for any other task to perform work) you can use the following code within your async block :

async {
         ....
         let! token = myAsyncTask |> Async.StartChild
         let! result = token
         ....  
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top