locked
Issue with FSharpChart RRS feed

  • Question

  • Hello,

    I built the following F# function to benchmark subroutines and I'm having an issue where the chart (which supports observables) behaves like an IEnumerable and displays the data only after OnComplete is called.

    I figured this isn't the ideal place to ask the question but despite that, I believe it's the place I'm most likely to find a solution (thumbs up Rx'ers).

    The following works as intended:

    Observable.Interval(TimeSpan.FromMilliseconds(500.0)).Take(10) |> FSharpChart.Line |> FSharpChart.WithCreate |> ignore
    


    i.e. The graph is interactive and updates as long as the stream isn't over.

     

    While my function only displays the graph once completed:

    type Obs = System.Reactive.Linq.Observable
    let map (f : 'Ts -> 'Tr) obs = Observable.Select(obs, f)
    let sub (f : 'T -> unit) obs = ObservableExtensions.Subscribe(obs, Action<'T>(f))
    
    let bench f max =
      Obs.Range(0, 20)
      |> map (fun o -> o * max / 20)
      |> Obs.Timestamp
      |> map (fun o -> f o.Value |> ignore; (o.Value, (DateTime.Now - o.Timestamp.DateTime).TotalMilliseconds))
      |> (fun o -> Obs.Buffer(o, 3, 1))
      |> map (fun o -> (o |> Seq.averageBy (fst >> float), o |> Seq.averageBy snd))
      |> FSharpChart.Line
      |> FSharpChart.WithCreate
      |> ignore
    


    Thanks for any help.

    David

    Thursday, July 21, 2011 9:24 PM

Answers

  • Hi David,

    I don't know F#, but if you're saying that your query works as expected when using Observable.Interval but it does not when using Observable.Range, then it's probably because Interval introduces concurrency by default and Range does not.

    Try passing in Scheduler.ThreadPool to Observable.Range.

    - Dave


    http://davesexton.com/blog
    • Marked as answer by David Grenier Thursday, July 21, 2011 10:00 PM
    Thursday, July 21, 2011 9:56 PM

All replies

  • Hi David,

    I don't know F#, but if you're saying that your query works as expected when using Observable.Interval but it does not when using Observable.Range, then it's probably because Interval introduces concurrency by default and Range does not.

    Try passing in Scheduler.ThreadPool to Observable.Range.

    - Dave


    http://davesexton.com/blog
    • Marked as answer by David Grenier Thursday, July 21, 2011 10:00 PM
    Thursday, July 21, 2011 9:56 PM
  • Totally did fix the problem thanks for the awesome quick reply.

    Also, adding the following before FSharpChat.Line also fixed it (but admitedly crashed once):

    |> (fun o -> Obs.SubscribeOn(o, System.Reactive.Concurrency.Scheduler.TaskPool))
    


    I assume your solution is the correct one. I will review the difference between ObserveOn and SubscribeOn as I do not yet understand the purpose of each.

    Thanks again!

    Thursday, July 21, 2011 10:02 PM
  • Hi David,

    SubscribeOn is another solution to the problem, but it's not the recommended one.  It's better to specify the required scheduling at the source to avoid the overhead of any unneeded asynchrony that the source already provides.

    I don't know why it's causing your program to crash though :)  Could you post the exception stack trace?  I'm curious to know whether it's a bug in Rx or in FSharpChart.

    For a brief comparison between SubscribeOn and ObserveOn, see this discussion:

    http://social.msdn.microsoft.com/Forums/en-US/rx/thread/6944f097-00f4-42ad-8f19-d01d1aa939f4

    - Dave


    http://davesexton.com/blog
    Thursday, July 21, 2011 10:14 PM
  • It crashed with an error that reminisces me of another issue I have with FSharpChart. Somehow when I build a collection using the Enumerable operators (Seq.init, etc) it will refuse to work with the collection without me introducting a toArray at the very end.

    I don't believe it was a bug with Rx and despite trying I could not reproduce the problem.

    Thanks for the info.

    Thursday, July 21, 2011 10:30 PM