I'm experiencing different behaviour with an TakeUntil and different implementations of IObservable as the parameter. I'm trying to understand WHY i get the different behaviour. Using Linqpad:
async Task Main()
{
var byTimer = true;
var ending = Observable.FromEvent<long>(
handler => endingHandler += handler,
handler => endingHandler -= handler);
var s = new Subject<long>();
using (var disposibleSub =
Observable
.Interval(TimeSpan.FromSeconds(.2))
.TakeUntil(byTimer ? Observable.Timer(TimeSpan.FromSeconds(1.5)) : ending)
.DumpLatest()
.Subscribe(Observer.Checked(s)))
{
if (endingHandler != null)
{
int r = Console.Read();
endingHandler?.Invoke(r);
}
var v = await s.Count();
Console.WriteLine("Count of items: {0}", v);
}
}
public event Action<long> endingHandler;
The one with the timer Count always returns the correct value. However, if I change it to use the FromEvent implementation, I always get 0. Obviously the difference is in the implementation of the two. I've also tried using a Subject implementation for the TakeUntil with the same results as the fromEvent.
The timer result is what I expected.
An explanation why would be appreciated! Thanks.
When byTimer is true then the ending observable never gets a subscription - remember that the observable pipeline is only instantiated when a subscription arrives - so in this case the handler => endingHandler += handler attach event code doesn't run and thus endingHandler is null. That means that the Console.Read() isn't called so the code drops immediately to var v = await s.Count(); and this then catches all of the values passing thru s.
However, when byTimer is false then endingHandler is not null so then Console.Read() is called. When the console is read you immediately invoke endingHandler which stops the observable and calls OnCompleted on the subject. So when it hits var v = await s.Count(); it immediately gets a completed signal, missing all of the previously produced values, and thus you get a count of zero.
If you change your code to be like this:
int r = Console.Read();
if (endingHandler != null)
{
endingHandler?.Invoke(r);
}
var v = await s.Count();
Then the two observables behave exactly the same way.
If you then also go and change the Subject to ReplaySubject then the code should behave as you were originally expecting it to.
Related
I'm looking for a way to implement the following:
A says: "Yo, X happened. Bye."
Others see that and start doing some work.
In other words, I would like to fire an event and let others handle that in a fire and forget way.
So I've looked into the observer pattern: https://msdn.microsoft.com/en-us/library/dd783449(v=vs.110).aspx. However this example is synchronous, and if the observers take a long time to do their work, the notify method blocks for a long time.
I also looked at how to raise events: https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx. Also this example is synchronous, and blocks the sender for a long time when the handler takes long to handle the event.
My question is:
How do I do fire and forget events/messages/delegates in C#?
Probably you should meet Task Parallel Library (TPL) Dataflows. There's one data flow called ActionBlock<TInput> that should be a good start for you:
The ActionBlock<TInput> class is a target block that calls a delegate
when it receives data. Think of a ActionBlock<TInput> object as a
delegate that runs asynchronously when data becomes available. The
delegate that you provide to an ActionBlock<TInput> object can be of
type Action or type System.Func<TInput, Task>[...]
Therefore, what about giving a Func<TInput, Task> to ActionBlock<TInput> to perform asynchronous stuff? I've modified the sample found on this TPL Dataflow MSDN article:
List<Func<int, Task>> observers = new List<Func<int, Task>>
{
n => Console.WriteLine(n),
n => Console.WriteLine(n * i),
n => Console.WriteLine(n * n / i)
};
// Create an ActionBlock<int> object that prints values
// to the console.
var actionBlock = new ActionBlock<int>
(
n =>
{
// Fire and forget call to all observers
foreach(Func<int, Task> observer in observers)
{
// Don't await for its completion
observer(n);
}
}
);
// Post several messages to the block.
for (int i = 0; i < 3; i++)
{
actionBlock.Post(i * 10);
}
// Set the block to the completed state
actionBlock.Complete();
// See how I commented out the following sentence.
// You don't wait actions to complete as you want the fire
// and forget behavior!
// actionBlock.Completion.Wait();
You might also want to take a look at BufferBlock<T>.
Consider the following:
[Fact]
public void foo()
{
var result = new Subject<bool>();
var startCount = 0;
var completionCount = 0;
var obs = Observable
.Defer(() =>
{
++startCount;
return result.FirstAsync();
})
.Do(_ => ++completionCount)
.Publish()
.RefCount();
// pretend there are lots of subscribers at once
var s1 = obs.Subscribe();
var s2 = obs.Subscribe();
var s3 = obs.Subscribe();
// even so, we only expect to be started once
Assert.Equal(1, startCount);
Assert.Equal(0, completionCount);
// and we won't complete until the result ticks through
result.OnNext(true);
Assert.Equal(1, startCount);
Assert.Equal(1, completionCount);
s1.Dispose();
s2.Dispose();
s3.Dispose();
// now try exactly the same thing again
s1 = obs.Subscribe();
s2 = obs.Subscribe();
s3 = obs.Subscribe();
// startCount is 4 here instead of the expected 2!
Assert.Equal(2, startCount);
Assert.Equal(1, completionCount);
result.OnNext(true);
Assert.Equal(2, startCount);
Assert.Equal(2, completionCount);
s1.Dispose();
s2.Dispose();
s3.Dispose();
}
My understanding of Publish + RefCount is that a connection to the source is maintained as long as there is at least one subscriber. Once the last subscriber disconnects, any future subscriber will re-initiate the connection to the source.
As you can see in my test, everything works perfectly the first time through. But the second time, the deferred observable inside the pipeline is executed once for every new subscriber.
I can see via the debugger that for the first group of subscribers, obs._count (which counts subscribers) increases for each call to Subscribe. But for the second group of subscribers, it remains zero.
Why is this happening and what can I do to rectify my pipeline?
The answer from #user631090 is close, but incorrect, so I thought I'd answer myself.
It's because Publish will immediately complete new subscribers if the stream it published has itself completed. You can kind of see that in the diagram here:
But it would have been nice if the diagram included a subscriber after the underlying stream completes.
To add to the confusion, Defer is still called for new subscribers. But its return value is simply ignored by Publish because of the initial stream completing.
I'm as yet unable to come up with a way to implement my intended use case. I thought perhaps using Multicast rather than Publish, creating a new subject as necessary. But I haven't been able to achieve that yet. And it seems rather painful for what I would think is a common use case.
It's because the underlying observable result has already completed. So each new subscriber is just getting the OnCompleted callback.
If ObservableDefer was creating a new sequence each time or one that didn't complete you would see the desired behavior.
e.g.
return result.FirstAsync().Concat(Observable.Never<bool>());
You will need to remove the Assert.Equal(1, completionCount);
I'm trying to create an async unit test for the project, but cannot understand how to wait for the async subject to complete:
[Test]
public async void MicroTest()
{
var value = 2;
var first = new AsyncSubject<int>();
var second = new AsyncSubject<int>();
first.Subscribe(_ =>
{
value = _;
second.OnCompleted();
});
first.OnNext(1);
// how to wait for the second subject to complete?
Assert.AreEqual(value, 1);
}
Sync version of this test is works well:
[Test]
public void MicroTest()
{
var value = 2;
var first = new Subject<int>();
var second = new Subject<int>();
first.Subscribe(_ =>
{
value = _;
second.OnCompleted();
});
first.OnNext(1);
Assert.AreEqual(value, 1);
}
AsyncSubject versus Subject
First off, it's worth pointing out that AsyncSubject<T> is not an asynchronous version of Subject<T>. Both are in fact free-threaded* (see footnote).
AsyncSubject is a specialization of Subject intended to be used to model an operation that completes asynchronously and returns a single result. It has two noteworthy features:
Only the last result is published
The result is cached and is available to observers subscribing after it has completed.
It is used internally in various places, including by the ToObservable() extension method defined on Task and Task<T>.
The issue with the test
Recall AsyncSubject<T> will only return the final result received. It does this by waiting for OnCompleted() so it knows what the final result is. Because you do not call OnCompleted() on first your test is flawed as the OnNext() handler - the lambda function passed in your Subscribe call - will never be invoked.
Additionally, it is invalid not to call OnNext() at least once on an AsyncSubject<T>, so when you call await second; you will get an InvalidOperationException if you haven't done this.
If you write your test as follows, all is well:
[Test]
public async void MicroTest()
{
var value = 2;
var first = new AsyncSubject<int>();
var second = new AsyncSubject<int>();
first.Subscribe(_ =>
{
// won't be called until an OnCompleted() has
// been invoked on first
value = _;
// you must send *some* value to second
second.OnNext(_);
second.OnCompleted();
});
first.OnNext(1);
// you must do this for OnNext handler to be called
first.OnCompleted();
// how to wait for the second subject to complete
await second;
Assert.AreEqual(value, 1);
}
About asynchronous tests
As a general rule I would avoid writing asynchronous tests that could wait forever. This gets particularly annoying when it causes resource drains on build servers. Use some kind of timeout e.g:
await second.Timeout(TimeSpan.FromSeconds(1));
No need to handle the exception since that is enough for the test to fail.
**I've borrowed this term from the COM lexicon. In this sense I mean that they, as with most of the Rx framework components, will generally run on whatever thread you happen to invoke their methods on. Being free-threaded doesn't necessarily mean being fully thread safe though. In particular, unlike AsyncSubject<T>, Subject<T> doesn't protect you from the Rx grammar violation of making overlapping calls to OnNext. Use Subject.Synchronize or Observable.Synchronize for this protection.*
I needed to alternate between two states with each state having a different interval time.
The best way I could think of doing this was to use Reactive Extensions' Observable.Generate
which is pretty awsome.
From what I read on msdn and other sites, Observable.Finally() should fire if the
observable "terminates gracefully or exceptionally". I was testing the following code
(in LINQPad) to see how it works, but I can not get .Finall() to fire at all.
var ia = TimeSpan.FromSeconds(1);
var ib = TimeSpan.FromSeconds(.2);
var start = DateTime.UtcNow;
var ct = new CancellationTokenSource();
var o = Observable.Generate(
true,
// s => !ct.IsCancellationRequested,
s => (DateTime.UtcNow-start) < TimeSpan.FromSeconds(3) && !ct.IsCancellationRequested,
s => !s,
s => s ? "on" : "off",
s => s? ib : ia)
// .TakeUntil(start+TimeSpan.FromSeconds(3))
.Concat(Observable.Return("end"));
o.Subscribe( s=> s.Dump(), ct.Token);
var t = o.ToTask(ct.Token);
t.ContinueWith(x => x.Dump("done"));
o.Finally(() => "finallY".Dump()); // never gets called?
Thread.Sleep(10000);
ct.Cancel();
If I make Thread.Sleep 10s, the observable sequence finishes and the Task.ContinueWith fires,
but not .Finally().
If I make Thread.Sleep 2s, the observable sequence is canceled and the Task.ContinueWith again fires,
but not .Finally().
Why not?
Look at the return type of the Finally method; should give you a hint. Just like the Concat method returns a new IObservable with the new sequence concatenated to it, but doesn't change the original, the Finally method returns a new IObservable that has that final action, but you're subscribing to the original IObservable. Put the following line in front of your Subscribe call and it'll work.
o = o.Finally(() => "finallY".Dump());
I agree it's an odd API choice though; I'd think of Finally as being more akin to Subscribe than to Concat. You're subscribing to the finally "event"; it's odd that the API forces you to create a completely new IObservable and then subscribe to that just to get the Finally thing to happen. Plus it allows a potential error (made evident if we use the function in your question) that if you subscribe twice to that new IObservable, your Finally function will execute twice. So you have to make sure that one of your subscriptions is on the "finallied" IObservable and the others are all on the original. Just seems unusual.
I guess the way to think about it is that Finally isn't meant to modify the observable, but rather to modify the subscription itself. i.e., they don't expect you typically to make openly-accessible named observables that have Finally things (var o = Observable.[...].Finally(...);) rather it's meant to go inline with the subscription call itself (var subscription = o.Finally(...).Subscribe(...);)
My scenario:
I have a computation that should be run about once a second. After it is run there should be a wait of about 200ms for other stuff to catch up. If the compuation is still running after a second it should be started a second time, but should the program should wait until it is finished and start the next computation 200ms after finishing.
The way I am doing it now:
_refreshFinished = new Subject<bool>();
_autoRefresher = Observable.Interval(TimeSpan.FromMilliseconds(1000))
.Zip(_refreshFinished, (x,y) => x)
.Subscribe(x => AutoRefresh(stuff));
The problem with this code is, that i see no way to put in a delay after a computation finished.
The Delay method only delays the first element of the observable collection. Usually this behaviour is the right once, since you would have to buffer an endless amount of elements if you wanted to buffer everyone, but since delaying the call to Autorefesh by 200ms delays the output of _refreshFinished by 200ms as well there would be no buffer overhead.
Basicly I want an Observable that fires every every MaxTime(some_call,1000ms) then gets delayed by 200ms or even better, some dynamic value. At this point i dont even really care about the values that are running through this, although that might change in the future.
I´m open to any suggestions
Observable.Generate() has a number of overloads which will let you dynamically adjust the time in which the next item is created.
For instance
IScheduler schd = Scheduler.TaskPool;
var timeout = TimeSpan.FromSeconds(1);
var shortDelay = TimeSpan.FromMilliseconds(200);
var longerDelay = TimeSpan.FromMilliseconds(500);
Observable.Generate(schd.Now,
time => true,
time => schd.Now,
time => new object(), // your code here
time => schd.Now.Subtract(time) > timeout ? shortDelay : longerDelay ,
schd);
This sounds more like a job for the new async framework http://msdn.microsoft.com/en-us/vstudio/gg316360
There is a way to do it. Its not the easiest thing ever, since the wait time has to be dynamicly calculated on each value but it works and is pretty generic.
When you use thise code you can just insert the code that should be called in YOURCODE and everything else works automaticly. You code will be basicly be called every Max(yourCodeTime+extraDelay,usualCallTime+extraDelay). This means yourCode wont be called twice at the same time and the app will always have extraDelay of time to do other stuff.
If there is some easier/other way to do this i would ove to hear it.
double usualCallTime = 1000;
double extraDealy = 100;
var subject = new Subject<double>();
var subscription =
sub.TimeInterval()
.Select(x =>
{
var processingTime = x.Interval.TotalMilliseconds - x.Value;
double timeToWait =
Math.Max(0, usualCallTime - processingTime) + extraDelay;
return Observable.Timer(TimeSpan.FromMilliseconds(timeToWait))
.Select(ignore => timeToWait);
})
.Switch()
.Subscribe(x => {YOURCODE();sub.OnNext(x)});
sub.OnNext(0);
private static void YOURCODE()
{
// do stuff here
action.Invoke();
}
If I understand your problem correctly, you have a long-running compute function such as this:
static String compute()
{
int t = 300 + new Random().Next(1000);
Console.Write("[{0}...", t);
Thread.Sleep(t);
Console.Write("]");
return Guid.NewGuid().ToString();
}
And you want to call this function at least once per second but without overlapping calls, and with a minimum 200ms recovery time between calls. The code below works for this situation.
I started with a more functional approach (using Scan() and Timestamp()), more in the style of Rx--because I was looking for a good Rx exercise--but in the end, this non-aggregating approach was just simpler.
static void Main()
{
TimeSpan period = TimeSpan.FromMilliseconds(1000);
TimeSpan recovery = TimeSpan.FromMilliseconds(200);
Observable
.Repeat(Unit.Default)
.Select(_ =>
{
var s = DateTimeOffset.Now;
var x = compute();
var delay = period - (DateTimeOffset.Now - s);
if (delay < recovery)
delay = recovery;
Console.Write("+{0} ", (int)delay.TotalMilliseconds);
return Observable.Return(x).Delay(delay).First();
})
.Subscribe(Console.WriteLine);
}
Here's the output:
[1144...]+200 a7cb5d3d-34b9-4d44-95c9-3e363f518e52
[1183...]+200 359ad966-3be7-4027-8b95-1051e3fb20c2
[831...]+200 f433b4dc-d075-49fe-9c84-b790274982d9
[766...]+219 310c9521-7bee-4acc-bbca-81c706a4632a
[505...]+485 0715abfc-db9b-42e2-9ec7-880d7ff58126
[1244...]+200 30a3002a-924a-4a64-9669-095152906d85
[1284...]+200 e5b1cd79-da73-477c-bca0-0870f4b5c640
[354...]+641 a43c9df5-53e8-4b58-a0df-7561cf4b0483
[1094...]+200 8f25019c-77a0-4507-b05e-c9ab8b34bcc3
[993...]+200 840281bd-c8fd-4627-9324-372636f8dea3
[edit: this sample uses Rx 2.0(RC) 2.0.20612.0]
Suppose you have an existing 'IObservable' , then the following will work
var delay = TimeSpan.FromSeconds(1.0);
var actual = source.Scan(
new ConcurrentQueue<object>(),
(q, i) =>
{
q.Enqueue(i);
return q;
}).CombineLatest(
Observable.Interval(delay),
(q, t) =>
{
object item;
if (q.TryDequeue(out item))
{
return item;
}
return null;
}).Where(v => v != null);
'actual' is your resultant observable. But keep in mind that the above code has turned that into a Hot observable if it wasn't hot already. So you won't get 'OnCompleted' called.