none
Please help me understand RX a bit more...

    問題

  • In the online doc we see this example:

     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reactive;
    using System.Reactive.Linq;
    using System.Reactive.Subjects;
    
    namespace SimpleSequence
    {
        class Program
        {
            static void Main(string[] args)
            {
                IObservable<int> source = Observable.Range(1, 10);
                IDisposable subscription = source.Subscribe(
                    x => Console.WriteLine("OnNext: {0}", x),
                    ex => Console.WriteLine("OnError: {0}", ex.Message),
                    () => Console.WriteLine("OnCompleted"));
                Console.WriteLine("Press ENTER to unsubscribe...");
                Console.ReadLine();
                subscription.Dispose();
            }
        }
    }

    This example creates the observable through one of the Observable's methods. This works great where there are methods that meet one's needs. And due to the power of this new way of thinking my first question is:

    1) Is MSFT considering adding built-in Observable getter methods to everything we now see IEnumerables returned?

    In Example 2 they show this conversion:

    IEnumerable<int> e = new List<int> { 1, 2, 3, 4, 5 };
    
    IObservable<int> source = e.ToObservable();
    IDisposable subscription = source.Subscribe(
                                x => Console.WriteLine("OnNext: {0}", x),
                                ex => Console.WriteLine("OnError: {0}", ex.Message),
                                () => Console.WriteLine("OnCompleted"));
    Console.ReadKey();

    Which from a design point of view says, in a Model (of the MVVM architecure), IEnumerable is still king.  If we are using WCF or EF or even direct SQL command interfaces we see IEnumerable<ofSomeType> returned.  If the Model itself is running in it's own thread, there's no problem really with this design, but this brings me to question 2.

    2) Isn't using IEnumerable just 1 extra and eventually unnecessary step?  Shouldn't everything be able to return IObservable as well as IEnumerable (WCF services), EF loads etc.

    Finally, when we see the legacy Async operations starting with BeginGetXXXX EndGetXXXX like this code:

    public IAsyncResult BeginGetContext(
    	AsyncCallback callback,
    	Object state
    )

    3) How do we look at this signature with respect to getting Observables out of that?

    I'm just trying to wrap my head around how to think about the design of a project when I want to use Observables without getting tripped up with Legacy/Current signatures that are A) Not Lambda friendly (IAsyncResult, AsyncCallback), and B)  No IObservable interface

    4) When do we consider creating a Observable Provider? 

    and finally:

    5) Should we look to LINQ to get conversions from IEnumerables to IObservables in lieu of creating providers?

     

    JP Cowboy Coders Unite!



    2012年3月29日 下午 02:20

解答

  • Hi,

    > 1) Is MSFT considering adding built-in Observable getter methods to everything we now see IEnumerables returned?

    I can't answer on behalf of Microsoft, obviously, but I assume the answer would be no.

    I think you're conflating two ideas though.  Recall that enumerables represent a synchronous (pull) sequence, while observables represent an asynchronous (push) sequence.  So perhaps it would be better to ask the following two questions instead:

    1. Will the FCL contain asynchronous alternatives for all APIs that currently return IEnumerable<T>?
    2. If yes, will the FCL's asynchronous alternatives return IObservable<T>?

    I think the answer to #1 is no.  Not every API has an underlying asynchronous model, nor does it makes sense for every API to have an underlying asynchronous model.  Though if the answer was yes, then I suspect the answer to #2 would be yes as well.

    Perhaps some existing FCL methods could have asynchronous alternatives, though I'm not sure how useful they'd be; e.g., Directory.EnumerateFiles.  Again, not every API has an underlying asynchronous model, and I'm not sure if this one has a native Win32 model either.

    Also, keep in mind that Rx and IObservable<T> are not about injecting concurrency into everything.  It's purely about modeling asynchrony.  Sometimes concurrency makes sense, sometimes it doesn't.  In the case of FCL members that return IEnumerable<T>, it probably often doesn't make sense to inject concurrency artificially simply because you can easily convert them to IObservable<T> and execute them on a background thread.  Perhaps the primary reason for this is because it's so easy to do already:

    SomeFCLMemberReturnsIE().ToObservable(NewThreadScheduler.Default);

    > Which from a design point of view says, in a Model (of the MVVM architecure), IEnumerable is still king.

    How do you figure that?  I believe it depends entirely on whether a reactive model is what you need to meet a specific requirement.  If it is, then I'd certainly use IObservable<T> instead of IEnumerable<T> at the source, whenever possible.

    > 2) Isn't using IEnumerable just 1 extra and eventually unnecessary step?
    > Shouldn't everything be able to return IObservable as well as IEnumerable (WCF services), EF loads etc.

    In fact, anything that IEnumerable<T> can do IObservable<T> can do better, with a single conversion operator required for synchronous iteration; however, IEnumerable<T> is an apt model for synchronous computations, so I see no reason why it should be replaced entirely.  Sometimes that's exactly the model you want, so it makes sense to have an identifying type.  Furthermore, C# offers compiler support for things like foreach and iterator blocks.  Although I'd love to see native support for async iterators in C# in the future, currently we'll just have to make due with IEnumerable<T>.

    As for WCF and EF specifically, I'd agree that having entirely native asynchronous methods would be a very good thing.  Though I don't agree that they should entirely replace the existing synchronous model, for the reasons stated above.

    > [snip] 3) How do we look at this signature with respect to getting Observables out of that?

    Observable.FromAsyncPattern, which is obsolete as of Rx 2.0 Beta in favor of the new Observable.FromAsync method for converting from task-based asynchrony.

    Note that Rxx provides many wrappers for quickly converting FCL members into observables, many of which use the Asynchronous Programming Model (APM).  Rxx is especially useful for the more complicated APIs; e.g., those that implement the Event-Based Asynchronous Pattern (EBAP).

    > 4) When do we consider creating a Observable Provider?

    1. When you have an asynchronous API that you want to use as an observable, then you can convert it in several different ways.  See the following documentation and note that Rx 2.0 Beta now offers additional conversion methods for working with task-based asynchrony.
      http://msdn.microsoft.com/en-us/library/hh242978(v=vs.103).aspx
      http://msdn.microsoft.com/en-us/library/hh242960(v=vs.103).aspx
    2. When you have a synchronous API that you want to use asynchronously by injecting concurrency, consider using Observable.Start.
    3. When you want to create your own observable to generate an asynchronous sequence, consider using any of the methods in the first category of the following document:
      http://msdn.microsoft.com/en-us/library/hh242961(v=vs.103).aspx

    > 5) Should we look to LINQ to get conversions from IEnumerables to IObservables in lieu of creating providers?

    Edit: Sorry, I may have misunderstood this question.  I think you're asking whether it makes sense to start with an enumerable and then convert it into an observable instead of using one of the Rx generator operators.  I'd say yes in some cases and no in others.  It depends on your requirements.  For example, if you need a range of data then don't do Enumerable.Range(1, 10).ToObservable(), simply use Observable.Range.  If you have a list of data and you want to create a hot observable, then simply calling ToObservable is fine.  There are of course more complicated scenarios, so if you have any in mind in particular, then start a new post and I'm sure you'll get answer(s).

    My previous answer to #5:
    No.  LINQ is a model for composing queries independently of the type of the sequence.  LINQ operators are provided for IEnumerable<T> and IObservable<T>.  For conversions, use the conversion operators:

    http://msdn.microsoft.com/en-us/library/hh242961(v=vs.103).aspx

    - Dave


    http://davesexton.com/blog

    2012年3月29日 下午 05:02