I have tried to write console observable as in the example below, but it doesn't work. There are some issues with subscriptions. How to solve these issues?
static class Program
{
static async Task Main(string[] args)
{
// var observable = Observable.Interval(TimeSpan.FromMilliseconds(1000)).Publish().RefCount(); // works
// var observable = FromConsole().Publish().RefCount(); // doesn't work
var observable = FromConsole(); // doesn't work
observable.Subscribe(Console.WriteLine);
await Task.Delay(1500);
observable.Subscribe(Console.WriteLine);
await new TaskCompletionSource().Task;
}
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(Console.ReadLine());
}
});
}
}
If I used Observable.Interval, it subscribes two times and I have two outputs for one input. If I used any version of FromConsole, I have one subscription and a blocked thread.
To start with, it is usually best to avoid using Observable.Create to create observables - it's certainly there for that purpose, but it can create observables that don't behave like you think they should because of their blocking nature. As you've discovered!
Instead, when possible, use the built-in operators to create observables. And that can be done in this case.
My version of FromConsole is this:
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
Observable.Start effectively is like Task.Run for observables. It calls Console.ReadLine() for us without blocking.
The Observable.Defer/Repeat pair repeatedly calls Observable.Start(() => Console.ReadLine()). Without the Defer it would just call Observable.Start and repeatedly return the one string forever.
That solves that.
Now, the second issue is that you want to see the value from the Console.ReadLine() output by both subscriptions to the FromConsole() observable.
Due to the way Console.ReadLine works, you are getting values from each subscription, but only one at a time. Try this code:
static async Task Main(string[] args)
{
var observable = FromConsole();
observable.Select(x => $"1:{x}").Subscribe(Console.WriteLine);
observable.Select(x => $"2:{x}").Subscribe(Console.WriteLine);
await new TaskCompletionSource<int>().Task;
}
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
When I run that I get this kind of output:
1:ddfd
2:dfff
1:dfsdfs
2:sdffdfd
1:sdfsdfsdf
The reason for this is that each subscription starts up a fresh subscription to FromConsole. So you have two calls to Console.ReadLine() they effectively queue and each one only gets each alternate input. Hence the alternation between 1 & 2.
So, to solve this you simply need the .Publish().RefCount() operator pair.
Try this:
static async Task Main(string[] args)
{
var observable = FromConsole().Publish().RefCount();
observable.Select(x => $"1:{x}").Subscribe(Console.WriteLine);
observable.Select(x => $"2:{x}").Subscribe(Console.WriteLine);
await new TaskCompletionSource<int>().Task;
}
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
I now get:
1:Hello
2:Hello
1:World
2:World
In a nutshell, it's the combination of the non-blocking FromConsole observable and the use of .Publish().RefCount() that makes this work the way you expect.
The problem is that the Console.ReadLine is a blocking method, so the subscription to the FromConsole sequence blocks indefinitely, so the await Task.Delay(1500); line is never reached. You can solve this problem by reading from the console asynchronously, offloading the blocking call to a ThreadPool thread:
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(await Task.Run(() => Console.ReadLine()));
}
});
}
You can take a look at this question about why there is no better solution than offloading.
As a side note, subscribing to a sequence without providing an onError handler is not a good idea, unless having the process crash with an unhandled exception is an acceptable behavior for your app. It is especially problematic with sequences produced with Observable.Create<T>(async, because it can lead to weird/buggy behavior like this one: Async Create hanging while publishing observable.
You need to return a observable without the publish. You can then subscribe to it and do your thing further. Here is an example. When I run it i can readline multiple times.
public class Program
{
static void Main(string[] args)
{
FromConsole().Subscribe(x =>
{
Console.WriteLine(x);
});
}
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(Console.ReadLine());
}
});
}
}
Related
I have encountered something strange when using System.Reactive. Maybe this is the regular behavior but makes little sense to me.
Let's take following code:
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> I = Observable.Interval(TimeSpan.FromSeconds(1));
async Task Main()
{
X.Switch().Subscribe(x => Console.WriteLine($"switched_1: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_1: {x}"));
X.Switch().Subscribe(x => Console.WriteLine($"switched_2: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_2: {x}"));
await Task.Factory.StartNew(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false);
X.Switch().Subscribe(x => Console.WriteLine($"switched_3 !!!: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_3: {x}"));
});
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.ReadLine();
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.WriteLine("New observable emited");
Console.ReadLine();
}
The observable marked with !!! is never hit until the second Interval is emitted.
[Update]
I think I know what's happening: I am subscribing to the upstream observable each time with a new switch. And while I am doing this, I will get notified only about the observable emitted after the subscription, and I can not "connect" to the current observable.
I thought that by using switch only once, and subscribe to the resulting observable later will help:
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> XI;
void Main()
{
XI = X.Switch().AsObservable();
XI.Subscribe(x => Console.WriteLine($"switched_1: {x}"));
XI.Subscribe(x => Console.WriteLine($"switched_2: {x}"));
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
XI.Subscribe(x => Console.WriteLine($"switched_3 !!!: {x}"));
Console.ReadLine();
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.WriteLine("New observable emited");
Console.ReadLine();
}
But did not :(
[Update 2]
It seems that I have found a solution that actually works, but I am not sure if it is correctly used or not.
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> XI;
async Task Main()
{
XI = X.Switch().Publish().AutoConnect();
...
How can I make it work form the very beginning?
Your explanation under [Update] is correct because Task.Factory.StartNew is returning a Task<Task> instead of a Task. You have to use a double await or Task.Run if you want that the subscription happens before you call OnNext().
However only exposing a XI-Observable as in [Update2] and hide the fact that there is something switched underneath is a viable option.
With Publish().AutoConnect() you transform the observable from cold to hot. You can also try out a BehaviorSubject or a ReplaySubject on your snippet to understand the differences between hot & cold. If you understand these differences it should be much clearer for you, how the actual solution you have in mind has to look like.
I'm current reading http://www.introtorx.com/ and I'm getting really interested in stripping Subject<T> out of my reactive code. I'm starting to understand how to encapsulate sequence generation so that I can reason better about a given sequence. I read a few SO questions and ended up reading about scheduling. Of particular interest is recursive scheduling, using the Schedule(this IScheduler scheduler, Action<TState,Action<TState>>)overloads - like this one.
The book is starting to show its age in a few areas, and the biggest i see is that it never compares its techniques to alternatives that may be achieved using the Task and async/await language features. I always end up feeling like I could write less code by ignoring the book advice and using the asynchronous toys, but the back of my mind nags me about being lazy and not learning the pattern properly.
With that, here is my question. If I wanted to schedule a sequence at an interval, support cancellation and perform work on a background thread, I might do this:
static void Main(string[] args)
{
var sequence = Observable.Create<object>(o =>
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
DoWerk(o, cancellationTokenSource);
return cancellationTokenSource.Cancel;
});
sequence.Subscribe(p => Console.Write(p));
Console.ReadLine();
}
private static async void DoWerk(IObserver<object> o, CancellationTokenSource cancellationTokenSource)
{
string message = "hello world!";
for (int i = 0; i < message.Length; i++)
{
await Task.Delay(250, cancellationTokenSource.Token);
o.OnNext(message[i]);
if (cancellationTokenSource.IsCancellationRequested)
{
break;
}
}
o.OnCompleted();
}
Note the use of async void to create concurrency without explicitly borrowing a thread pool thread with Task.Run(). await Task.Delay() will, however, do just that but it will not lease the thread for long.
What are the limitations and pitfalls here? What are the reasons that you might prefer to use recursive scheduling?
I personally wouldn't use await Task.Delay(250, cancellationTokenSource.Token); as a way to slow down a loop. It's better than Thread.Sleep(250), but it's still code smell to me.
I would look at it that you should use a built-in operator in preference to a roll-your-own solution like this.
The operator you need is one of the most powerful, but often overlooked. Try Observable.Generate. He's how:
static void Main(string[] args)
{
IObservable<char> sequence = Observable.Create<char>(o =>
{
string message = "hello world!";
return
Observable
.Generate(
0,
n => n < message.Length,
n => n + 1,
n => message[n],
n => TimeSpan.FromMilliseconds(250.0))
.Subscribe(o);
});
using (sequence.Subscribe(p => Console.Write(p)))
{
Console.ReadLine();
}
}
This is self-cancelling (when you call .Dispose() on the subscription) and produces values every 250.0 milliseconds.
I've continued to use the Observable.Create operator to ensure that the message variable is encapsulated within the observable - otherwise it is possible for someone to change the value of message as the observable is working with it and thus break it.
As an alternative, that might not be as efficient with memory, but is self-encapsulating, try this:
IObservable<char> sequence =
Observable
.Generate(
"hello world!",
n => !String.IsNullOrEmpty(n),
n => n.Substring(1),
n => n[0],
n => TimeSpan.FromMilliseconds(250.0));
And, finally, there's nothing "recursive" about the scheduling in your question. What did you mean by that?
I finally figured out what you're looking at. I missed it in the question.
Here's an example using the recursive scheduling:
IObservable<char> sequence = Observable.Create<char>(o =>
{
string message = "hello world!";
return Scheduler.Default.Schedule<string>(message, TimeSpan.FromMilliseconds(250.0), (state, schedule) =>
{
if (!String.IsNullOrEmpty(state))
{
o.OnNext(state[0]);
schedule(state.Substring(1), TimeSpan.FromMilliseconds(250.0));
}
else
{
o.OnCompleted();
}
});
});
I'm interested in an ActionBlock implementation for Framework 4.0, since there it seems that TPL.Dataflow isn't supported for Framework 4.0.
More particularly, I'm interested in the case of the constructor that receives the Func<TInput, Task> delegate and the MaxDegreeOfParallism = 1 case.
I thought about implementing it using reactive extensions, but I'm not sure how to do it. Thought about creating a Subject<TInput> and calling OnNext on Post, and using SelectMany and task ToObservable stuff, but I'm not sure what to do with the scheduler. Here is a draft of what I was thinking of.
public class ActionBlock<TInput>
{
private readonly TaskCompletionSource<object> mCompletion = new TaskCompletionSource<object>();
private readonly Subject<TInput> mQueue = new Subject<TInput>();
public ActionBlock(Func<TInput, Task> action)
{
var observable =
from item in mQueue
from _ in action(item).ToObservable()
select _;
observable.Subscribe(x => { },
OnComplete);
}
private void OnComplete()
{
mCompletion.SetResult(null);
}
public void Post(TInput input)
{
mQueue.OnNext(input);
}
public Task Completion
{
get
{
return mCompletion.Task;
}
}
public void Complete()
{
mQueue.OnCompleted();
}
}
I thought maybe using EventLoopScheduler but I'm not sure it fits here since this is async.
Any ideas?
mQueue
.Select(input => Observable.FromAsync(() => action(input))
.Merge(maxDegreeOfParallelism)
.Subscribe(...);
If indeed maxDegreeOfParallelism is always 1, then just use Concat instead of Merge:
mQueue
.Select(input => Observable.FromAsync(() => action(input))
.Concat()
.Subscribe(...);
This works because FromAsync just creates a cold observable that will not run the async action until it is subscribed. We then use the maxConcurrency parameter of Merge (or just Concat) to limit the number of concurrent subscriptions (and thus the number of async actions running).
Edit:
And since your goal is to just have a Task that represents the completion of the stream, you can use ToTask instead of directly subscribing. ToTask will subscribe and return a Task with the final value. Because ToTask will throw if the observable does not produce a value, we'll use Count to guarantee it produces a value:
// task to mark completion
private readonly Task mCompletion;
// ...
this.mCompletion = mQueue
.Select(input => Observable.FromAsync(() => action(input))
.Concat()
.Count()
.ToTask();
I am stuck at correctly disposing Threads, created with RX, on application exiting. I see in Process Explorer that after application closed, threads are still running, causing an IO exceptions.
class Program
{
static void Main(string[] args)
{
CompositeDisposable subsriptions = new CompositeDisposable();
subscriptions.Add(Observable.Interval(TimeSpan.FromSeconds(15))
.Subscribe(_ =>
{
getData();
}));
Thread.Sleep(TimeSpan.FromSeconds(20));
subscriptions.Dispose();
}
}
}
If you see if I uncomment the subscription.Dispose(), the thread terminates without getting any data. Any help would be appreciated. Thanks
You need some sort of delay between subsriptions.Add(...) and subscriptions.Dispose(). Without a delay between there, your app is simply subscribing and disposing them immediately, with no time for the threads to do their work. (And the Thread.Sleep(1000) doesn't work, since it is inside the subscription function, not part of the main function.)
The pattern you are looking for is similar to this
class Program {
public string GetData(){
return "Hello";
}
public string async GetDataAsync(){
return await Observable
.Interval(TimeSpan.FromSeconds(15))
.Take(1)
.Select(()=>GetData());
}
static void Main(string[]args){
var s = GetDataAsync().Wait();
}
}
The reason for Wait is that an entry point, Main, in this case cannot be
marked as async. Wait blocks the current thread until the Task returned
by GetDataAsync produces a value.
Note also that IObservable is compatible with async/await and will return the last
value produced by the sequence. That is why I add Take(1) as it will produce
only 1 tick.
Another alternative is just to call Wait directly on the IObservable as in
class Program {
public string GetData(){
return "Hello";
}
public IObservable<string> GetDataObservable(){
return Observable
.Interval(TimeSpan.FromSeconds(15))
.Take(1)
.Select(()=>GetData());
}
static void Main(string[]args){
var s = GetDataObservable().Wait();
}
}
You can subscribe your observable with the CancellationToken that will cancel the underlying task execution:
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
Observable.
Interval(TimeSpan.FromSeconds(15)).
Subscribe(_ => getData(), cts.Token));
cts.CancelAfter(TimeSpan.FromSeconds(20));
}
I want to put Reactive Extensions for .NET (Rx) to good use and would like to get some input on doing some basic tasks. To illustrate what I'm trying to do I have a contrived example where I have an external component with asyncronous events:
class Component {
public void BeginStart() { ... }
public event EventHandler Started;
}
The component is started by calling BeginStart(). This method returns immediately, and later, when the component has completed startup, the Started event fires.
I want to create a synchronous start method by wrapping the component and wait until the Started event is fired. This is what I've come up with so far:
class ComponentWrapper {
readonly Component component = new Component();
void StartComponent() {
var componentStarted =
Observable.FromEvent<EventArgs>(this.component, "Started");
using (var startedEvent = new ManualResetEvent(false))
using (componentStarted.Take(1).Subscribe(e => { startedEvent.Set(); })) {
this.componenet.BeginStart();
startedEvent.WaitOne();
}
}
}
I would like to get rid of the ManualResetEvent, and I expect that Rx has a solution. But how?
PL's answer if perfectly good for your spec, but I thought you might get better results by not fighting RX with .First() but embracing it with creating an observable to your component:
public static IObservable<Unit> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return Observable
.FromEvent<EventArgs>(component, "Started")
.Select(_ => new Unit());
});
}
Then you could use it as blocking:
new Component().AsObservable().First();
Non - blocking:
new Component().AsObservable().Subscribe(_ => Console.WriteLine("Done"));
Hot:
var pub = new Component().AsObservable().Publish();
pub.Subscribe(_ => Console.WriteLine("Sub1"));
pub.Subscribe(_ => Console.WriteLine("Sub2"));
pub.Connect(); // started just once per two subscriptions
Composable:
new Component().AsObservable().Delay(TimeSpan.FromSeconds(1));
etc...
EDIT: For the case of multiple events that you have to wait on and collect information,
the following variation could be used:
public static IObservable<EventArgs> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return
Observable.FromEvent<EventArgs>(component, "Started1").Take(1)
.Merge(
Observable.FromEvent<EventArgs>(component, "Started2").Take(1))
.Select(evt => evt.EventArgs);
});
}
With this one, if you want to block till completion, you might use .AsObservable.Last().
Something like this should do it:
var replay = Observable
.FromEvent<EventArgs>(this.component, "Started")
.Replay();
replay.Connect();
component.BeginStart();
replay.First();