I'm trying to solve my first task using Rx + ReactiveUI and am looking for best practices to solve a task, showing a input box that will show up suggestions as soon as the user starts typing.
According to the following code sample, what is the best way to load suggestions asynchronosly? Using Subscribe or using Select Many? Or is there a better way to do this beneth these two?
this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
.Throttle(SuggestionThrottle, RxApp.MainThreadScheduler)
.Value()
.SelectMany(async s => await this.LoadSearchSuggestions(s)); // 1st Possibility
this.SearchTerms.Subscribe(this.LoadSearchSuggestions); // 2nd Possibility
You must call Subscribe either way.
Queries in Rx use lazy evaluation, which means that merely defining a query does not start it. Lazy evaluation allows you to build a query by applying operators conditionally, to define a query only once and store it in a field for later, or to pass a reference around without causing any side effects until you call Subscribe.
Without calling Subscribe your query will remain inactive.
Subscribe activates the query by passing to the observable your IObserver<T>, or you can use its overloads that allow you to supply OnNext, OnError and/or OnCompleted handlers individually, which Rx converts into an IObserver<T> for you. It is the IObserver<T> that receives the query's notifications.
There is a parameterless overload of Subscribe that internally uses a silent observer, with the intention of starting your query for its side effects only. For example, in your case if you were to use SelectMany to do all of the work of loading the suggestions and you had no need for a separate IObserver<T>, then you would start the query by calling the parameterless overload of Subscribe.
In most cases you shouldn't use the parameterless overload of Subscribe. The point of Subscribe is that the IObserver<T> (or the individual handlers) that you pass to it are intended to cause the side effects of your query. By only causing side effects in either Subscribe or, for instance, the Do operator, a query is much easier to reason about and to maintain.
However, there is one fairly common scenario where using the parameterless overload of Subscribe makes sense: If the side effects of your query are caused by an asynchronous method, then using SelectMany along with the parameterless overload of Subscribe is best.
The reason is simple: SelectMany is the sequential composition operator, which enables you to call an asynchronous method as a sequential step inside your query. Therefore, SelectMany ties the cancellation of the subscription to the cancellation of your asynchronous computation. Disposing of a subscription (represented by the IDisposble that is returned from the call to Subscribe) causes the CancellationToken provided by special asynchronous overloads of the SelectMany operator to be signaled for cancellation. Your asynchronous method can monitor the CancellationToken to exit its computation early.
There aren't any overloads of Subscribe that accept an asynchronous observer, whereby OnNext returns a Task. But even if you were to call a void-returning asynchronous method in your OnNext handler, your asynchronous method wouldn't be signaled when the subscription is disposed.
Note that both of your code samples are slightly wrong anyway. The first example has no need for the async and await keywords. As stated above, there are special overloads of SelectMany that accept a Task<T>-returning selector function, and additional overloads that provide a CancellationToken to that function. You should probably be using the latter.
Your second example shouldn't compile, presuming that LoadSearchSuggestions returns Task. (Unless the ReactiveUI library or some other library that you're referencing is providing an overload of Subscribe that accepts a Task-returning function, in which case you'll have to consult their documentation.)
Barring the latter, and assuming that the rest of your query is correct, here's what you should do:
this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
.Throttle(SuggestionThrottle, RxApp.MainThreadScheduler)
.Value()
.SelectMany(LoadSearchSuggestionsAsync)
.Subscribe();
where LoadSearchSuggestionsAsync is defined like this:
async Task<Unit> LoadSearchSuggestionsAsync(string term, CancellationToken cancel)
{
...
return Unit.Default;
}
Note that Unit represents void in Rx. It's required because an asynchronous method that returns a non-generic Task cannot be used with SelectMany. If you have actual data to return instead, then simply replace Unit with the type of your data. Then you can also pass an OnNext handler to Subscribe and do something with the return value, such as logging.
Related
I'm learning to do rx in .NET the right way and wondering what is the usual way to make an observable stream out of a remote function call.
At the moment, I just create a Subject<T> and call its OnNext function within the callback method.
Example:
subject.AsObservable().Where(...).Subscribe(...);
This is where I filter and subscribe to the observable.
await speechService.StartListeningAsync(f => OnSpeechCommandRecognized(f),
cts.Token, OnError, interimResults).ConfigureAwait(false);
This is where I pass the callback method to the speech service.
private void OnSpeechCommandRecognized(StreamingRecognitionResult result)
{
subject.OnNext(result);
}
This is where I call the OnNext function within the callback method.
Another way I was looking at was to call Observable.Start and subscribe to the returning observable, but I don't think this is the way to go.
Also i could wrap the call around an Observable.Create.
So my question is: Is this example the right way to subscribe to a method emitting results?
What if you used Create rather than a Subject?
Since your API returns a task which presumably won't complete until it's time to stop listening, you can use FromAsync to wrap that call and then create a closure to the Create's observer. Subscribe to the inner observable, and you have an observable which, when subscribed to, will yield results from the StartListeningAsync callback until the associated task completes (or errors).
Observable.Create((observer, outerCancel) =>
Observable.FromAsync(innerCancel =>
speechService.StartListeningAsync(
observer.OnNext,
innerCancel,
observer.OnError,
interimResults
))
.Subscribe(observer, outerCancel)
);
Does anyone have a steer on when to use one of these methods over the other. They seem to do the same thing in that they convert from TPL Task to an Observable.
Observable.FromAsync appear to support cancellation tokens which might be the subtle difference that allows the method generating the task to participate in cooperative cancellation if the observable is disposed.
Just wondering if I'm missing something obvious as to why you'd use one over the other.
Thanks
Observable.FromAsync accepts a TaskFactory in the form of Func<Task> or Func<Task<TResult>>,
in this case, the task is only created and executed, when the observable is subscribed to.
Where as .ToObservable() requires an already created (and thus started) Task.
#Sickboy answer is correct.
Observable.FromAsync() will start the task at the moment of subscription.
Task.ToObservable() needs an already running task.
One use for Observable.FromAsync is to control reentrancy for multiple calls to an async method.
This is an example where these two methods are not equivalent:
//ob is some IObservable<T>
//ExecuteQueryAsync is some async method
//Here, ExecuteQueryAsync will run **serially**, the second call will start
//only when the first one is already finished. This is an important property
//if ExecuteQueryAsync doesn't support reentrancy
ob
.Select(x => Observable.FromAsync(() => ExecuteQueryAsync(x))
.Concat()
.ObserveOnDispatcher()
.Subscribe(action)
vs
//ob is some IObservable<T>
//ExecuteQueryAsync is some async method
//Even when the `Subscribe` action order will be the same as the first
//example because of the `Concat`, ExecuteQueryAsync calls could be
//parallel, the second call to the method could start before the end of the
//first call.
.Select(x => ExecuteQueryAsync(x).ToObservable())
.Concat()
.Subscribe(action)
Note that on the first example one may need the ObserveOn() or ObserveOnDispatcher() method to ensure that the action is executed on the original dispatcher, since the Observable.FromAsync doesn't await the task, thus the continuation is executed on any available dispatcher
Looking at the code, it appears that (at least in some flows) that Observable.FromAsync calls into .ToObservable()*. I am sure the intent that they should be semantically equivalent (assuming you pass the same parameters e.g. Scheduler, CancellationToken etc.).
One is better suited to chaining/fluent syntax, one may read better in isolation. Whichever you coding style favors.
*https://github.com/Reactive-Extensions/Rx.NET/blob/859e6159cb07be67fd36b18c2ae2b9a62979cb6d/Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/QueryLanguage.Async.cs#L727
Aside from being able to use a CancellationToken, FromAsync wraps in a defer so this allows changing the task logic based upon conditions at the time of subscription. Note that the Task will not be started, internally task.ToObservable will be called. The Func does allow you to start the task though when you create it.
In Async/Await FAQ, Stephen Toub says:
An awaitable is any type that exposes a GetAwaiter method which returns a valid awaiter.
...
An awaiter is any type returned from an awaitable’s GetAwaiter method and that conforms to a particular pattern.
So in order to be an awaiter, a type should:
Implement the INotifyCompletion interface.
Provide a boolean property called IsCompleted.
Provide a parameterless GetResult method that returns void or TResult.
(I'm ignoring ICriticalNotifyCompletion for now.)
I know the page I mentioned has a sample that shows how the compiler translates await operations but I'm stil having a hard time understanding.
When I await an awaitable,
When is IsCompleted checked? Where should I set it?
When is OnCompleted called?
Which thread calls OnCompleted?
I saw examples of both directly invoking the continuation parameter of OnCompleted and using Task.Run(continuation) in different examples, which should I go for and why?
Why would you want a custom awaiter?
You can see the compiler's interpretation of await here. Essentially:
var temp = e.GetAwaiter();
if (!temp.IsCompleted)
{
SAVE_STATE()
temp.OnCompleted(&cont);
return;
cont:
RESTORE_STATE()
}
var i = temp.GetResult();
Edit from comments: OnCompleted should schedule its argument as a continuation of the asynchronous operation.
In the vast majority of cases, you as a developer need not worry about this. Use the async and await keywords and the compiler and runtime handle all this for you.
To answer your questions:
When does the code checks IsCompleted? Where should I set it?
The task should set IsCompleted when the task has finished doing what it was doing. For example, if the task was loading data from a file, IsCompleted should return true when the data is loaded and the caller can access it.
When does it calls OnCompleted?
OnCompleted usually contains a delegate supplied by the caller to execute when the task has completed.
Does it call OnCompleted in parallel or should the code
inside OnCompleted be asynchronous?
The code in OnCompleted should be thread neutral (not care which thread it is called from). This may be problematic for updating COM objects in Single Threaded Apartments (like any UI classes in Metro/Windows8/Windows Store apps). It does not have to be asynchronous but may contain asynchronous code.
I saw examples of both directly invoking the continuation parameter of OnCompleted
and using Task.Run(continuation) in different examples, which should I go for and when?
Use async/await when you can. Otherwise, use Task.Run() or Task.Wait() because they follow the sequential programming model most people are used to. Using continuations may still be required, particularly in Metro apps where you have apartment issues.
I wrote an implementation based on the examples at [ Rx DEVHOL202] and http : //rxwiki.wikidot.com/101samples#toc48
Here is my code. http://csharp.pastebin.com/pm2NAPx6
It works, but the calls to OnNext are not NonBlocking, which is what i would like to implement to simulate a network read and asynchronously handing off each chunk of bytes as it is read to a handler [ which is not shown here in full but might cache results and do further processing ].
What is a good way of doing that?
Once the Exception gets thrown, all the subsequent OnNext()s are not processed!!
If I dont explicitly exit the loop and indicate completion.
Why is this so?
I would strongly recommend against trying to implement your own IObservable. The implicit rules go beyond thread safety and into method call ordering.
Usually you would return IObservable instances from methods, but if you need a class that implements it directly, you should wrap a Subject:
public class SomeObservable<T> : IObservable<T>
{
private Subject<T> subject = new Subject<T>();
public IDisposable Subscribe(IObserver<T> observer)
{
return subject.Subscribe(observer);
}
}
1. You need to be careful about how you support this from your observer (as you may have shared data), but you can make your handling of the calls asynchronous in one of two ways:
Call ObserveOn(Scheduler.TaskPool) (or ThreadPool if you are pre-4.0) before you call Subscribe. This causes messages to be routed through a scheduler (in this case, a task)
Pass the IScheduler to the Observer constructor
Start an asynchronous task/thread from your subscriber
2. This is the expected functionality. The contract between IObservable and IObserver is (OnNext)* (OnCompleted | OnError)?, which is to say "zero or more calls to OnNext, optionally followed by EITHER OnCompleted or OnError". After OnCompleted|OnError, it is invalid to call OnNext.
All the operators in Rx (Where, Select, etc) enforce this rule, even if the source doesn't.
I'm not sure if I understand your question correctly, but why can't you just execute whatever logic you have on a different Thread, or if it's small enough push it on a ThreadPool?
Here is an example:
ThreadPool.QueueUserWorkItem(o=>
{
_paidSubj.OnNext(this); // Raise PAID event
});
I'm confused about the data type on Subject, I have never seen that class in C#... is it something that you created? Is OnNext an event that gets raised or is it just a method? If OnNext is an event, then you can use BeginInvoke to invoke it asynchronously:
_paidSubj.OnNext.BeginInvoke(this, null, null);
Update:
An important thing that will happen if you implement this kind of asynchronous behavior: if you notify an IObserver by passing the Order, you might actually have some inconsistencies when you try to read the data in the observer (namely the order buffer) while the Order continues to modify the buffer in its Read thread. So there are at least two ways to solve this:
Restrict access to the memory which will get modified by using locks.
Only notify the observer with the relevant information that you want it to see:
a. By passing the information as a value (not as a reference).
b. By creating an immutable structure that transmits the information.
P.S.
Where did you get Subject from? Is Subject supposed to be an OrderObserver?
I am just curious to know that why the return type of an asynchronous call in c# is IAsynceResult ?
What else would it be? It can't be the "final" result of the call, as that won't be known yet. Basically it's a value representing the asynchronous call, so that you can later determine whether it's completed, what the result was etc.
It's a shame it's not generic (in the result type) for non-void async calls, but that's due to the legacy of .NET 1 not supporting generics.
EDIT: I nearly mentioned Task<T> originally. The trouble is, there are a lot of places where the method is already declared to return IAsyncResult, and you can't just go changing APIs left, right and centre. I do occasionally wonder how much cleaner .NET would be if MS had waited for generics before releasing. Of course that sort of argument is always applicable, but for generics it's particularly important IMO.
Because it's an asynchronous call, the actual end result is not yet known. So, the return type is essentially your reference to the call you have made so you can keep track of when it completes.
Think of it a bit like a ticket you get when you drop a parcel off to be delivered via recorded/tracked delivery - that ticket gives you a means to check the progress of the delivery and follow it up later.
The IAsyncResult provides the ability to monitor the progress of an asynchronous call, as well as to provide a 'token' that can later be passed to the 'Complete___' method of the async pair of methods that you typically see.
Since the asynchronous call cannot return the actual value of the operation, this interface provides a container for the state of that call that later enables you to get the result.
This is especially important when considering that you might have multiple asynchronous calls to the same method outstanding - the IAsyncResult instance helps identify each of them individually.
Because of classic async pattern implementation.
IAsyncResult object returns from the Begin method and represents a single asynchronous operation. It contains methods and properties providing access to some basic information about the asynchronous operation.
Making an asynchronous call is like asking someone to go and do something at their convenience. The IAsyncResult is a handle to that request. You can use it to wait for the task to complete, to query the progress, and get any result and/or exception from the task. What would prefer instead?