Throttle calls from multiple sources to a single method - c#

I'm a bit stumped because I have a hard time finding any relevant info to my question. I'm very new to System.Reactive, so maybe I'm using it wrong.
I have a number of objects that all call a static method during an event. I want to limit the calls to that method.
public class MyObject
{
public MyObject ()
{
var observable = Observable.FromEventPattern<SizeChangedEventHandler, SizeChangedEventArgs>
(handler => SizeChanged += handler, handler => SizeChanged -= handler);
observable.Throttle (TimeSpan.FromMilliseconds (100));
observable.Subscribe (x =>
{
MethodToCall (this);
});
}
static void MethodToCall (MyObject obj)
{
// Do something.
}
}
Now, that obviously doesn't work because it only throttles calls from this single object which occur well less often than 100ms. What I think I need is some kind of static Observable that accumulates all calls and then dispatches a call after 100ms. Can anyone give me some pointers?
Update:
I implemented it with the help of a Stopwatch, which also seems to do the job. I'm still curious about a Reactive solution though.
private static Stopwatch sw = new Stopwatch();
private static void MethodToCall(MyObjectv)
{
if (sw.ElapsedMilliseconds < 100 && sw.IsRunning)
{
return;
}
// Some code here
if (sw.IsRunning)
{
sw.Restart();
}
else
{
sw.Start();
}
}

You can use the observable in the MethodToCall method implementation instead:
private static Subject<MyObject> subject = new Subject<MyObject>();
private static IDisposable subscription = subject
.Throttle (TimeSpan.FromMilliseconds (100))
.Subscribe(v =>
{
// Some code here
});
private static void MethodToCall(MyObject v)
{
subject.OnNext(v);
}
Then, the throttling becomes an internal implementation detail of MethodToCall.

Related

What does SetValue do in this particular event?

I am new to events and I am trying to see how an event works and what purpose they would have. The code below is some code that a friend helped me with that we found on the net. It works but I am not certain as to how the event is used.
In the Main method there is the EventTest which creates a new object e which then intern calls SetValue method twice with a different parameter.
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
The following code is actually the event code.The OnNumChanged is the event that writes information if the number is changed. So when SetValue(100) is set to a different number then the event is fired.
Question: When the SetValue is set with a new value this is what cause the event to change correct?
I am just new enough to the event change that I could really use some good examples or have someone really explain this example line by line.
e.SetValue(7);
e.SetValue(11);
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();
}
else
{
Console.WriteLine("Event fired!");
}
}
Code:
class Program
{
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
}
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
public EventTest(int n)
{
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();
}
else
{
Console.WriteLine("Event fired!");
}
}
}
Yes, you are correct:
public void SetValue(int n)
{
if (value != n) // check if the value actually changed
{
value = n;
OnNumChanged(); // call the event "in a save way", see below
}
}
protected virtual void OnNumChanged()
{
if (ChangeNum != null) // check if someone is listening - PROBLEM: see below
ChangeNum(); // trigger the event and call all event handlers registered
}
The Problem I mentioned above: You get the event to check it for null and then get it again to execute. In a multi-threaded environment it can happen, that between these two "gets" it changes => create a local copy:
protected virtual void OnNumChanged()
{
var changeNum = ChangeNum;
if (changeNum != null)
changeNum();
}
To actually get notified on the event you need to register for the event e.g. like this:
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.ChangeNum += () => Console.WriteLine("Num changed"); //<== this
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
It also would make more sense to also supply the new value in the event. That can be done by altering the delegate to:
public delegate void NumManipulationHandler(int newValue);
and call it like:
ChangeNum(value);
Then you can register like:
e.ChangeNum += newValue => Console.WriteLine("Num changed to " + newValue);
in short: yes! if the value that is passed along with the SetValue method differs from the one that was already stored, an event is fired, indicating the change as such.
Any other code that might be subscribed to such an event can then react accordingly in whatever way.
Even though I myself can learn easier from video (and I advise you to search for videos on events in C# as well), it all boils down to a way for a class to provide notifications to clients of that class when some interesting thing happens to an object (further reading here)

c# asynchronously call method

There is this class unit that has a property bool status that marks whether a method, request, should be called on the unit. I have my other class, and in it, there is a method that should call request. To avoid blocking the main thread, I want to call the method asynchronously. The problem is that there isn't an event for the status change, and I don't want to make my asynchronous call do ugly stuff like:
while(!status){}unit.request(args);
or
while(!status){Thread.Sleep(100)}unit.request(args);
especially when I do not know the timescale in which status turns true.
How do I do this?
update: i forgot to mention that i cannot change unit. sorry for that.
You want to call a function (be it asynchronously or not) when a property changes. You have two choices:
Attach to an even that is signalled when the property changes
Periodically check the value of the property
You can't do the first, so you must do the second.
This is a sample of how you can manage this using an event.
Suppose this is your class
public class Unit
{
private readonly object _syncRoot = new object();
private bool _status;
public event EventHandler OnChanged;
public bool Status
{
get
{
lock (_syncRoot)
{
return _status;
}
}
set
{
lock (_syncRoot)
{
_status = value;
if (_status && OnChanged != null)
{
OnChanged.Invoke(this, null);
}
}
}
}
public void Process()
{
Thread.Sleep(1000);
Status = true;
}
}
Here is how you can use it
class Program
{
static void Main(string[] args)
{
var unit = new Unit();
unit.OnChanged += Unit_OnChanged;
Console.WriteLine("Before");
Task.Factory.StartNew(unit.Process);
Console.WriteLine("After");
Console.WriteLine("Manual blocking, or else app dies");
Console.ReadLine();
}
static void Unit_OnChanged(object sender, EventArgs e)
{
//Do your processing here
Console.WriteLine("Unit_OnChanged before");
Task.Factory.StartNew(()=>
{
Thread.Sleep(1000);
Console.WriteLine("Unit_OnChanged finished");
});
Console.WriteLine("Unit_OnChanged after");
}
}
This outputs
Before
After
Manual blocking, or else app dies
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged finished
This is the classic polling problem, and there really isn't an elegant solution when polling is concerned. But we can work some functional programming in to get something which isn't a nightmare to use.
public static CancellationTokenSource Poll(
Func<bool> termination,
Action<CancellationToken> onexit,
int waitTime = 0,
int pollInterval = 1000)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
Action dispose = cts.Cancel;
var timer = new Timer(_ =>
{
if (termination() || token.IsCancellationRequested)
{
onexit(token);
dispose();
}
}, null, waitTime, pollInterval);
dispose = timer.Dispose;
return cts;
}
Example:
var condition = false;
Poll(() => condition == true, ct => Console.WriteLine("Done!"));
Console.ReadLine();
condition = true;
Console.ReadLine();
Use a System.Threading.AutoResetEvent instead of a bool if possible:
AutoResetEvent status = new AutoResetEvent();
In your asynchronous method, wait for it:
status.WaitOne();
unit.request(args);
Then, to signal it in your other class, call Set:
status.Set();

Syncronizing actions in Silverlight

I have a Silverlight app that uses actions to get data from the model (which again gets the data from WCF services).
I need to somehow sync two ActionCallbacks, or wait for them, and then execute some code.
Example:
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
});
doSomethingWhenBothHaveReturned();
I know I can use a counter to keep track of how many has returned, but is there not a better way to do this?
EDIT: user24601 has a good answer, but CountdownEvent does not exist in silverlight, any other great ideas? :)
Yes, a counter is what you need. The 'more elegant' solution would be to use a countdown event:
using (CountDownEvent countDownEvent = new CountDownEvent(2))
{
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
countDownEvent.Signal();
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
countDownEvent.Signal();
});
countdownEvent.Wait();
doSomethingNowThatWereComplete();
}
Solved the problem my self, using a counter:
public class ActionWaitHandler
{
private int _count;
private readonly Action _callback;
public ActionWaitHandler(int count, Action callback)
{
_count = count;
_callback = callback;
}
public void Signal()
{
_count--;
if (_count == 0)
{
_callback();
}
}
}
usage:
public void method() {
var handler = new ActionWaitHandler(2, OnActionsComplete);
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
handler .Signal();
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
handler .Signal();
});
}
public void OnActionsComplete()
{
dosomething;
}

Observer pattern with timer

I have used Observer Pattern for my application.
I have a subject which has one System.Timers.Timer object in it named 'tmr'. The tick event of this timer fires after every 60 seconds. On this tick event I will notify all my observers that are attached to my subject. I have used a for-loop to iterate throught my Observers List & then fire the Observers Update method.
Assume i have 10 observers attached to my subject.
Each observer takes 10 seconds to complete its processing.
Now notification being done in a for-loop causes the last Observer's Update method to be called after 90seconds. i.e. Next Observer Update method is called only after previous one has completed its processing.
But this is not what i wanted in my application. I need all my observers Update method to be fired instantly when the timer tick occurs. So that no observer has to wait. I hope this can be done by Threading.
So, I modified code to,
// Fires the updates instantly
public void Notify()
{
foreach (Observer o in _observers)
{
Threading.Thread oThread = new Threading.Thread(o.Update);
oThread.Name = o.GetType().Name;
oThread.Start();
}
}
But I have two doubts in my mind,
If there are 10 observers
And my timer interval is 60 seconds
Then the statement new Thread() will fire 600 times.
Is it efficient and recommended to create new threads on every timer tick ?
What if my observers are taking too much time to complete their update logic i.e. goes more than 60seconds. Means the timer tick occurs before the observers are updated. How can i control this ?
I can post sample code.. if required...
The code i used..
using System;
using System.Collections.Generic;
using System.Timers;
using System.Text;
using Threading = System.Threading;
using System.ComponentModel;
namespace singletimers
{
class Program
{
static void Main(string[] args)
{
DataPullerSubject.Instance.Attach(Observer1.Instance);
DataPullerSubject.Instance.Attach(Observer2.Instance);
Console.ReadKey();
}
}
public sealed class DataPullerSubject
{
private static volatile DataPullerSubject instance;
private static object syncRoot = new Object();
public static DataPullerSubject Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new DataPullerSubject();
}
}
return instance;
}
}
int interval = 10 * 1000;
Timer tmr;
private List<Observer> _observers = new List<Observer>();
DataPullerSubject()
{
tmr = new Timer();
tmr.Interval = 1; // first time to call instantly
tmr.Elapsed += new ElapsedEventHandler(tmr_Elapsed);
tmr.Start();
}
public void Attach(Observer observer)
{
_observers.Add(observer);
}
public void Detach(Observer observer)
{
_observers.Remove(observer);
}
// Fires the updates instantly
public void Notify()
{
foreach (Observer o in _observers)
{
Threading.Thread oThread = new Threading.Thread(o.Update);
oThread.Name = o.GetType().Name;
oThread.Start();
}
}
private void tmr_Elapsed(object source, ElapsedEventArgs e)
{
tmr.Interval = interval;
tmr.Stop(); // stop the timer until all notification triggered
this.Notify();
tmr.Start();//start again
}
}
public abstract class Observer
{
string data;
public abstract void Update();
public virtual void GetDataFromDBAndSetToDataSet(string param)
{
Console.WriteLine("Processing for: " + param);
data = param + new Random().Next(1, 2000);
Threading.Thread.Sleep(10 * 1000);//long work
Console.WriteLine("Data set for: " + param);
}
}
public sealed class Observer1 : Observer
{
private static volatile Observer1 instance;
private static object syncRoot = new Object();
public static Observer1 Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Observer1();
}
}
return instance;
}
}
Observer1()
{
}
public override void Update()
{
base.GetDataFromDBAndSetToDataSet("Observer1");
}
}
public sealed class Observer2 : Observer
{
private static volatile Observer2 instance;
private static object syncRoot = new Object();
public static Observer2 Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Observer2();
}
}
return instance;
}
}
Observer2()
{
}
public override void Update()
{
base.GetDataFromDBAndSetToDataSet("Observer2");
}
}
}
Thanks & kind regards.
Using new Thread is discouraged. Use Task or Task<T>
Your best attempt at creating an Observable pattern framework will probably only come close to Rx. Use that which solves the problems you mentioned (i.e. if processing takes too much time). Rx will give you huge flexibility in defining your observable scenarios.
1) You can use Threads from the ThreadPool via ThreadPool.QueueUserWorkItem or you can use Tasks
2) You have to synchronize your Methods.
Alternatively, the observers could implement Update in a non-blocking way.
That is, Update always returns immediately. Then it is the responsibility of the Observer objects to perform their work in a new thread if necessary.
I'm not sure if this helps in your scenario - I don't know what your 'Observers' are, but then maybe you don't know either?

Call Method B if method A is not called for more than N seconds

I'm using following code to call Method B after N seconds method A is called. If method A
is called again within the N seconds timeout, i have to reset the time counting back to N seconds.
I cannot reference System.Windows.Form in my project, so I cannot use System.Windows.Form.Timer.
The method B must be called in the same thread A is called.
private void InitTimer()
{
timer = new BackgroundWorker();
timer.WorkerSupportsCancellation = true;
timer.WorkerReportsProgress = true;
timer.DoWork += delegate(object sender, DoWorkEventArgs e)
{
var st = DateTime.Now;
while (DateTime.Now.Subtract(st).TotalSeconds < 10)
{
if (timer.CancellationPending)
{
e.Cancel = true;
return;
}
}
};
timer.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled)
{
MethodB();
}
else
{
timer.RunWorkerAsync();
}
};
}
public void MethodA()
{
if (timer.IsBusy)
timer.CancelAsync();
else
timer.RunWorkerAsync();
}
public void MethodB()
{
//do some stuff
}
Actually the code work, but i think it's a bit confounding. Do you know if there is a best practices to achieve the same result?
It's a shame you're stuck on .NET 2.0, because Rx extensions has a Throttle method that achieves this effect quite elegantly.
Sadly Rx requires at least .NET 3.5 SP1.
Oh well! You can always use a System.Threading.Timer to get this done instead. Synchronization can be provided by leveraging the current SynchronizationContext (this is what BackgroundWorker does).
Here's a sketch of a LaggedMethodPair class to illustrate this approach. The class takes three inputs in its constructor: an Action to be performed on-demand, another Action to serve as the callback that will be invoked when a given timeout has elapsed, and, of course, the timeout itself:
public sealed class LaggedMethodPair
{
private SynchronizationContext _context;
private Timer _timer;
private Action _primaryAction;
private Action _laggedCallback;
private int _millisecondsLag;
public LaggedMethodPair(Action primaryAction,
Action laggedCallback,
int millisecondsLag)
{
if (millisecondsLag < 0)
{
throw new ArgumentOutOfRangeException("Lag cannot be negative.");
}
// Do nothing by default.
_primaryAction = primaryAction ?? new Action(() => { });
// Do nothing by default.
_laggedCallback = laggedCallback ?? new Action(() => { });
_millisecondsLag = millisecondsLag;
_timer = new Timer(state => RunTimer());
}
public void Invoke()
{
// Technically there is a race condition here.
// It could be addressed, but in practice it will
// generally not matter as long as Invoke is always
// being called from the same SynchronizationContext.
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext()
);
}
_context = SynchronizationContext.Current;
ResetTimer();
_primaryAction();
}
void ResetTimer()
{
_timer.Change(_millisecondsLag, Timeout.Infinite);
}
void RunTimer()
{
_context.Post(state => _laggedCallback(), null);
}
}
I wrote a sample Windows Forms app to show this class in action. The form contains a LaggedMethodPair member with a timeout of 2000 ms. Its primaryAction adds an item to a list view. Its laggedCallback adds a highlighted item to the list view.
You can see that the code runs as expected.
I would encapsulate this functionality into a timer class with events that other classes can subscribe to (for example a timer.tick event).
I am trying to use AutoResetEvent, because it is capable to wait for a signal. I use it to have worker waited for the signal from A(), and if it has been too long B() will be called.
class Caller
{
AutoResetEvent ev = new AutoResetEvent(false);
public void A()
{
ev.Set();
// do your stuff
Console.Out.WriteLine("A---");
}
void B()
{
Console.Out.WriteLine("B---");
}
public void Start()
{
var checker = new BackgroundWorker();
checker.DoWork += new DoWorkEventHandler(checker_DoWork);
checker.RunWorkerAsync();
}
void checker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (!worker.CancellationPending)
{
bool called = ev.WaitOne(TimeSpan.FromSeconds(3));
if (!called) B();
}
}
}
I have tested my class roughly and it is working fine so far. Note that B will be called from worker thread, so you have to do the synchronization in B() if needed.

Categories

Resources