I need to make a function that works on it is won thread to do announcements in its determinate time, for example:
"Visit our website at : ...." set to run every 5 minutes
"Check your place on the rank at : ...." set to run every 10 minutes
I am a bit confused if I should use a thread timer or a thread while with sleep and how to calculate when every announcements should run.
To get started I was considering the a list of a class to hold each announcement to be made, something like List<MyTimer> with the class as:
public MyTimer
{
public string Announcement { get; set; }
public int Interval { get; set; } // if interval is 0 means
// it will run just once
public bool hasSpecificTime { get; set; } // if this is true then will run
// only once at the SpecificTime
public bool Done { get; set; }
public DateTime SpecificTime { get; set; }
}
Specific time announcements will be removed after used.
As for the thread I was thinking of using something like this:
Timer = new System.Threading.Timer(TimerCallback, null, 0, 1000);
private void TimerCallback(object state)
{
foreach (var item in timerList)
{
// not sure how to handle the intervals of each continuous announcement
// some code here for the the above
// Not sure if this would work either because of the milliseconds etc
// on the DateTime
if (item.hasSpecificTime && !item.Done && SpecificTime == DateTime.Now)
{
SendAnnouncement(item.Announcement);
item.Done = true;
}
}
}
Is my implementation OK for what I need ?
How do I handle the interval and times within the function as I said in the question I am not sure on how to get it calculated to send it on the correct time ?
You need to change
item.hasSpecificTime && !item.Done && SpecificTime == DateTime.Now
to
item.hasSpecificTime && !item.Done && SpecificTime <= DateTime.Now
otherwise you will almost all events.
If your timerList grow large you should move completed items to a separate list instead to avoid looping through lots of completed items all the time.
Edit
You also need to increase SpecificTime with Interval for the recurring events.
You can create more elaborate schemes, but your code is simple to read and understand and that is very important.
One scheme you can use is to store the MyTimer instances in an ordered queue where you keep the closest SpecifiedTime first. You can then schedule the TimerCallback to the duration until the first element in the queue instead of repeatedly polling a complete list. You need to have some more book-keeping too. If you insert a new item in the queue and that item happens to be the next to be executed (comes first in the queue) you need to cancel and restart your timer.
This is more "elegant", but is only necessary if you have lots of events and suffer from performance issues (or the 1000 ms resolution is not granular enough).
Just a suggestion : Don't get offended please. But in this case you should try Rx operators which will be much cleaner and more maintainable than custom timer or thread implementation. Should thread implementation as much as possible as those are more complex to manage and maintain.
Related
I have a Windows Service, and I need run a method in a specific Schedules. So far I implement a class that represent a schedule.
public class SchaduleTime
{
public int Hour { get; set; }
public int Minute { get; set; }
public DateTime Next
{
get
{
var now = DateTime.Now;
var dt = now.Date;
// the time has passed to execute today?
if (Hour * 60 + Minute < now.Hour * 60 + now.Minute)
{
dt = dt.AddDays(1);
}
return new DateTime(dt.Year, dt.Month, dt.Day, Hour, Minute, 0);
}
}
}
And I create a main class that have this fields:
System.Timers.Timer timer;
private SchaduleTime[] schadules;
And run something like that in Elapsed event of the timer field:
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// do my work.
// programing next:
var nowTicks = DateTime.Now.Ticks;
// get the next schadule.
var next = schadules
.Select(s => new
{
Schadule = s,
IntervalNeeded = s.Next.Ticks - nowTicks
})
.OrderBy(o => o.IntervalNeeded)
.First();
timer.Enabled = false;
timer.Stop();
timer.Interval = (int) new TimeSpan(next.IntervalNeeded).TotalMilliseconds;
timer.Enabled = true;
timer.Start();
}
To me this seems like a kludge strategy or spaghetti code, I mean seems ugly.
Is there a way to do this using a specialized class that works with scheduling or something like Windows Task Scheduler inside .net or my approach is good and I'm freaking out?
Let's consider hypothetical situation where you got 10 schedules for 14:00. Say your timer stopped at 13:59:59, what happens is:
10 schedules claim they got 1 more second to go
elapsed handler picks first and restarts itself with 1 second interval
it stops again at 14:00 - right when all the schedules are already returning Next for the following day
As a result, you've run 1 out of your 10 jobs. Doesn't look good.
Of course, you could take list, or make limitation that only 1 job can be set for given hour. But then again, what other assumptions you need to make? Can schedules array be empty? Does it work when there's 1 million schedules? Do you have tests for this code? And so on.
Instead, you can use specialized library to do just that - Quartz. It's a simple jobs scheduler which can surely do what you're trying to implement here:
ISchedulerFactory factory= new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
scheduler.Start();
// You'll have to implement class performing actual work to be done - ServiceJob
JobDetail jobDetail = new JobDetail("ServiceJob", null, typeof(ServiceJob));
Trigger trigger = TriggerUtils.MakeDailyTrigger();
// Start time could be anytime today
trigger.StartTimeUtc = DateTime.UtcNow;
trigger.Name = "ServiceTrigger";
scheduler.ScheduleJob(jobDetail, trigger);
Quartz takes care of all the timers, running specified jobs at requested time and so forth. It's easy, has good set of tutorials and well - you don't have to implement anything.
In my opinion, your approach is fine. Actually, it is sort of inspired. I would not have come up with having one timer and permanently rescheduling it.
What I would have done - and this is strictly optional, like I said, your approach is fine - is just have the timer fire every minute and check if there is something to do. With smaller time resolution, seconds or even milliseconds, I would not do that. But having your timer run every minute, just checking an in-memory-array, and going straight back to sleep in 95% of cases is hardly a terrible waste of resources. Plus, it would allow for code that is much more straightforward and easier to maintain.
UPDATE: I've managed to fix my problem. Using the code below, I moved my MessageBox AFTER my XML saving and changed the Timer from 100ms to 400ms. I now have 1 box appear, thank god. Although If anyone has a short cut to updating a single value (ActReminded) in the List array(ActListTask), that'd be great to know.
I'm having a little issue with displaying the MessageBox. Show inside a timer without it spamming me. Here's the part of the code I've been working with:
public class ActiveTasks
{
//Properties here
}
public List<ActiveTasks> ActTaskList = new List<ActiveTasks>();
for (int i = 0; i < ListActive.Items.Count; i++)
{
if (DTime.Date == newDateTime.Date)
{
if (newDateTimeLeft.CompareTo(TimeSpan.Zero) <= 0 && ActTaskList[i].ActReminded != "true")
{
MessageBox.Show("!!!!");
ActTaskList.Add(new ActiveTasks()
{
ActTitle = ActTaskList[i].ActTitle,
ActDesc = ActTaskList[i].ActDesc,
ActDate = ActTaskList[i].ActDate,
ActTime = ActTaskList[i].ActTime,
ActStatus = ActTaskList[i].ActStatus,
ActReminded = "true",
ActRepeat = ActTaskList[i].ActRepeat
});
ListActive.Items.RemoveAt(i);
ActTaskList.RemoveAt(i);
XDocument XmlActTasks = GenerateActiveListToXML(ActTaskList);
}
}
}
I actually decided I may want to hold onto the reminder status, whether it has been shown or not as I wouldn't want a repeated reminder every time the program is opened. Since I don't know of a way to update an individual part of ActTaskList I just re-added it, and then deleted the original. This code manages to recognise that if it happens, it will change the reminder status from false, to true; after I've Ok'ed all the spam. So it will stop the MessageBox once I've managed to closed all the Messageboxes. However, it doesn't stop the spam. Would it be anything to do with the fact I've set the timer to 100ms? Or could their be an alternative way to make the messagebox appear without it being inside the timer?
The odds of the current time lining up exactly to the second what is happening in your loop is small. Why not treat newDateTime as a cut off point and just set a flag?
//Declare this outside of the loop
bool hasDisplayed = false;
//Inside the timer event handler
if (!hasDisplayed && DateTime.Now >= newDateTime)
{
hasDisplayed = true;
MessageBox.Show("!!!!!!!!!!!!!");
}
Can you do something like this?
Action message = () => MessageBox.Show("!!!!!!!!!!!!!"));
object lockOb = new object();
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
lock(lockOb)
if(null != message)
{
message();
message = null;
}
}
You say you've already tried a boolean indicating the message has already been shown, I'm assuming because the code probably looked like it did below.
void TimerLoop()
{
bool msgAlreadyShown;
if(!msgAlreadyShown)
{
MessageBox.Show("!!!!!!!");
}
// Other work in your timer function
}
The problem with that code is that the bool will be set to false each time the function is called by the timer. You haven't posted much code, but you've at least stated what you're trying to accomplish, a timer that checks if a reminder should be presented to the user.
I'm about to make some wild guesses about how you've put together your software, there's a good chance it's way off, but I hope it might point you in the right direction. You could have some sort of reminder class like this:
public class Reminder
{
string Message { get; set;}
DateTime Alarm { get; set; }
bool IsDismissed { get; set; }
}
I'm assuming you might want to have multiple reminders that can be checked for in the timer loop, so your timer loop could look something like:
private List<Reminder> _activeReminders; // A list of reminders
void TimerLoop(object s, ElapsedEventArgs e)
{
lock(_activeReminders)
{
var now = DateTime.Now;
foreach(var reminder in _activeReminders)
{
// only run this code if the time has passed and it hasn't already
// been shown
if(now.CompareTo(reminder.Alarm) >= 0 && !reminder.IsDismissed)
{
MessageBox.Show(reminder.Message);
reminder.IsDismissed = true;
}
}
}
}
This is a pretty naive implementation, since you probably don't want to hold onto the reminders for forever and the reminders are never removed from the _activeReminders list, but you essentially just need to add some sort of state to determine if the reminder has already been shown.
Of course, this isn't a complete example either, since I never new up the _activeReminders field or add anything to it, but I think this might help get the idea of what you need to do across. Also, you might not care about multiple reminders, and your timer code could look nothing like this. The main idea was to show you how you can keep track of the state of a reminder, and tailor it to your own code. The above was just an example.
Also, I haven't actually tested it, so treat it more like pseudocode than anything else. However, the logic is sound, and should it should only cause the message box to appear once.
I'm writing trading software and need to QoS one method that should not be executed more often than 10 times per second. As I'm begginer in C# and almost not familar with libraries I would like to double-check if my code is "optimal". I'm using Stopwatch because I don't know any other timers in C#.
Stopwatch updateStopwatch = Stopwatch.StartNew();
private void update()
{
if (updateStopwatch.ElapsedMilliseconds < 100)
{
Console.WriteLine("!skip update " + updateStopwatch.ElapsedMilliseconds);
return;
} else
{
Console.WriteLine("!update");
updateStopwatch.Restart();;
}
// do work here
}
upd Now it seems that Stopwatch is pretty good for this task. However probably it would be too slow, if so probably DateTime would be better. sell also Stopwatch vs. using System.DateTime.Now for timing events
Your technique of using Stopwatch is the best solution to prevent the code from executing more frequently. As others have said, using a Timer is a better solution if you want to make sure that the method is executed on a schedule.
Any approach based on DateTime is fundamentally broken because it will fail when the date changes. This is especially noticeable during the Daylight Saving Time switches. When we "spring ahead", there's the potential of the update running twice in quick succession because the code thinks that it's been an hour since the previous update. That's not too bad. But when we "fall back", the update will be suspended for a full hour because the last update time is set an hour ahead.
The same kind of thing can happen, although not as severely, if your computer is set to update its time periodically from an NTP server. If the time is set ahead, then there is the potential for two updates to happen in quick succession. If the time is set back, there's the potential for updates not to happen for the amount of time the clock was set back.
There are ways around the problem (such as using the absolute value of the number of milliseconds), but then you're just putting a bandage on a broken solution. You shouldn't depend on DateTime for intervals like this because your program isn't in control of the system clock--it can change at any time.
Stopwatch is the only reasonable solution here because it depends on the CPU's performance counter, which only increases. You don't have the problems of somebody setting the counter back, and you don't have the rollover problems you would encounter with something like Environment.TickCount.
There's some idea that Stopwatch incurs a performance penalty that DateTime doesn't. My testing shows that to be untrue.
Stopwatches and timers are fairly expensive objects to use. You could simply hold a DateTime object as a variable and perform a comparison.
DateTime lastCheck = DateTime.Now;
private void update()
{
// DateTime.Subtract returns a TimeSpan
int elapsed = DateTime.Now.Subtract(lastCheck).Milliseconds;
if (elapsed < 100)
{
Console.WriteLine("!skip update " + elapsed.ToString());
return;
} else
{
Console.WriteLine("!update");
lastCheck = DateTime.Now;
}
// do work here
}
I would not use a Stopwatch or anything other Timer-like. Instead just store the time of the method call and only execute the subsequent calls if the difference between the current and the stored time is bigger than 100ms.
You could implement a helper class to do this in a more general way:
public class TimedGate
{
private DateTime m_Last;
private TimeSpan m_Gap;
public TimedGate(TimeSpan gap)
{
m_Gap = gap;
}
public bool TryEnter()
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(m_Last) > m_Gap)
{
m_LastEntered = now;
return true;
}
return false;
}
}
Use it like this:
TimedGate m_UpdateGate = new TimedGate(TimeSpan.FromMilliseconds(100));
private void Update()
{
if (m_UpdateGate.TryEnter())
{
Console.WriteLine("!update");
// do work here
}
else
{
Console.WriteLine("!skip update");
}
}
There is always the System.Timer timer.
That is probably easier to work with than the Stopwatch (which normally is used to measure how long time things take).
Code:
var timer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer using a lambda
timer.Elapsed += (o, e) => Console.WriteLine("Timer elapsed");
// Set the Interval to 100 ms
timer.Interval = 100;
// Start the timer.
timer.Enabled = true;
MSDN docs: http://msdn.microsoft.com/en-us/library/system.timers.timer(v=VS.100).aspx
I'm working on a multi-threaded scraper for a website and as per a different question I've decided to use the ThreadPool with QueueUserWorkItem().
How can I continually Queue work items without queuing them all at once? I need to queue > 300k items (one for each userID) and if I loop to queue them all I'll run out of memory.
So, what I would like is:
// 1 = startUserID, 300000 = endUserID, 25 = MaxThreads
Scraper webScraper = new Scraper(1, 300000, 25);
webScraper.Start();
// return immediately while webScraper runs in the background
During this time, webScraper is continuouslly adding all 300000 workItems as threads become available.
Here is what I have so far:
public class Scraper
{
private int MaxUserID { get; set; }
private int MaxThreads { get; set; }
private static int CurrentUserID { get; set; }
private bool Running { get; set; }
private Parser StatsParser = new Parser();
public Scraper()
: this(0, Int32.MaxValue, 25)
{
}
public Scraper(int CurrentUserID, int MaxUserID, int MaxThreads)
{
this.CurrentUserID = CurrentUserID;
this.MaxUserID = MaxUserID;
this.MaxThreads = MaxThreads;
this.Running = false;
ThreadPool.SetMaxThreads(MaxThreads, MaxThreads);
}
public void Start()
{
int availableThreads;
// Need to start a new thread to spawn the new WorkItems so Start() will return right away?
while (Running)
{
// if (!CurrentUserID >= MaxUserID)
// {
// while (availableThreads > 0)
// {
// ThreadPool.QueueUserWorkItem(new WaitCallBack(Process));
// }
// }
// else
// { Running = false; }
}
}
public void Stop()
{
Running = false;
}
public static void process(object state)
{
var userID = Interlocked.Increment(ref CurrentUserID);
... Fetch Stats for userID
}
}
Is this the right approach?
Can anyone point me in the right direction for handling the creation of my work items while in the background once Start() is called, and not creating all Work items at once?
Would this be better implemented with less Work Items that steal work from a queue of work? Just because you have 300,000 pieces of work to do it doesn't mean you need 300,000 workers to do it. Obviously as you only have a few cores, only a few of these pieces of work can be happening in parallel, so why not hand out chunks of work to much fewer workers?
Depending on how constant the time taken for each piece of work is, you can either split it all evenly across each worker or have a central queue (that you'll have to lock around) and each worker can grab some work as it runs out.
EDIT:
Joe Duffy seems to have a series about writing a Work Stealing Queue here: http://www.bluebytesoftware.com/blog/2008/08/12/BuildingACustomThreadPoolSeriesPart2AWorkStealingQueue.aspx. It also looks like .Net 4's Threadpool is going to be a bit smarter. But I don't think you need something particularly complex for this scenario.
I think creating a queue of queued items doesn't seem quite right somehow, so how about making the WorkItems queue themselves again after they've finished?
Your Start method could queue up, say, 3 times MaxThreads items (75 in your example) and then your Process method queues itself when it's finished. That way your Start method returns quickly but fires off a number of work items, which as I say then fire themselves:
public class Scraper
{
private int MaxUserID { get; set; }
private int MaxThreads { get; set; }
private int currentUserID;
private bool Running { get; set; }
private Parser StatsParser = new Parser();
private int Multiplier { get; set; }
public Scraper()
: this(0, Int32.MaxValue, 25)
{
}
public Scraper(int currentUserID, int maxUserID, int maxThreads)
{
this.currentUserID = currentUserID;
this.MaxUserID = maxUserID;
this.MaxThreads = maxThreads;
this.Running = false;
ThreadPool.SetMaxThreads(maxThreads, maxThreads);
Multiplier = 3;
}
public void Start()
{
Running = true;
for (int i = 0; i < MaxThreads * Multiplier; i++)
{
ThreadPool.QueueUserWorkItem(Process);
}
}
public void Stop()
{
Running = false;
}
public void Process(object state)
{
if (Running == false)
{
return;
}
if (currentUserID < MaxUserID)
{
Interlocked.Increment(ref currentUserID);
//Parse stats for currentUserID
ThreadPool.QueueUserWorkItem(Process);
}
else
{ Running = false; }
}
}
I'm sure the Running flag should be being set using Interlocked for safety. I've made the multiplier into a property, which could be passed to the constructor - I'm fairly sure it could be adjusted to tweak performance, depending on how long those stats take to parse.
It looks like you need a Master process control class that governs the amount of workers that are firing off and keeps the Queue full.
You could work with two queues then:
One to hold all the items you need to scrape
Second to do the work
This Master/Governor object would then keep a loop until all your items from Queue #1 are gone and it would keep adding to Queue #2 when you have available cycles.
I definitely won't use ThreadPool.SetMaxThreads - remember that the threadpool is shared between all processes - setting the maximum amount of threads would simply kill performance. The whole idea behind the threadpool is that you don't need to specify things like the maximum amount of threads - the .Net framework figures out the optimum amount of threads to allocate - you don't need to do it.
Note that queuing 300 000 items would not cause 300 000 threads to spawn - the ThreadPool class will manage the number of threads for you and re-use threads as necessary. If you are simply worried that too many resources will be consumed this way I would recommend that you refine your process - perhaps create a 'Spawner' class which in turn runs 1000 of the scraper instances?
You can use a different thread pool. Here is one: http://www.codeplex.com/smartthreadpool
It allows you to queue up all your items at once. You can assign a max number of threads to create. Say you have 1000 work items and you assign 100 threads. It will immediately take the first 100 items and get them going while the rest wait. As soon as one of those items is done and a thread frees up, the next queued item is started. It manages all the work but won't saturate threads and memory. Also, it doesn't use threads from the .net thread pool.
Let's say I have an existing System.Threading.Timer instance and I'd like to call Change on it to push it's firing time back:
var timer = new Timer(DelayCallback, null, 10000, Timeout.Infinite);
// ... (sometime later but before DelayCallback has executed)
timer.Change(20000, Timeout.Infinite);
I'm using this timer to perform an "idle callback" after a period of no activity. ("Idle" and "no activity" are application-defined conditions in this case...the specifics aren't terribly important.) Every time I perform an "action", I want to reset the timer so that it is always set to fire 10 seconds after that.
However, there is an inherent race condition because when I call Change, I can't tell if the Timer has already fired based on its old settings. (I can, of course, tell if my callback has happened but I can't tell if the CLR's internal timer thread has queued my callback to the threadpool and its execution is imminent.)
Now I know I can call Dispose on the timer instance and re-create it each time I need to "push it back". but this seems less efficient than just changing the existing timer. Of course it may not be...I'll run some micro-benchmarks in a bit and let you all know.
Alternatively, I can always keep track of the expected firing time (via DateTime.Now.AddSeconds(10)) and, if the original Timer fires, ignore it by checking DateTime.Now in the callback. (I have a nagging concern that this may not be 100% reliable on account of the Timer using TimeSpan and my check using DateTime...this may not be an issue but I'm not completely comfortable with it for some reason...)
My questions are:
Is there a good way for me to call Timer.Change and be able to know whether I managed to change it before the callback was queued to the threadpool? (I don't think so, but it doesn't hurt to ask...)
Has anyone else implemented (what I term) a "pushback timer" like this? If so, I'd love to hear how you tackled the problem.
This question is somewhat hypothetical in nature since I already have a couple of working solutions (based on Dispose and based on DateTime.Now)...I'm mainly interested in hearing performance-related suggestions (as I'll be "pushing back" the Timer VERY frequently).
Thanks!
it sounds like what you really want is the application-idle event
System.Windows.Forms.Application.Idle
Im interpreting your questions as a request for an implementatation of the IdleNotifier interface specified below. Also you state that ActionOccured() needs to be fast.
public delegate void IdleCallback();
public interface IdleNotifier
{
// Called by threadpool when more than IdleTimeSpanBeforeCallback
// has passed since last call on ActionOccured.
IdleCallback Callback { set; }
TimeSpan IdleTimeSpanBeforeCallback { set; }
void ActionOccured();
}
I provide an implementation with System.Threading.Timer below.
Important points about the implementation:
We accept that the timer can wake up at any time and make sure this is ok.
Since we assume the timer wakes relatively seldom we can do expensive work at these times.
Since we can do all logic in the timer callback all we need to do to "push the timer" is to remeber when last we pushed it.
Implementation:
public class IdleNotifierTimerImplementation : IdleNotifier
{
private readonly object SyncRoot = new object();
private readonly Timer m_Timer;
private IdleCallback m_IdleCallback = null;
private TimeSpan m_IdleTimeSpanBeforeEvent = TimeSpan.Zero;
// Null means there has been no action since last idle notification.
private DateTime? m_LastActionTime = null;
public IdleNotifierTimerImplementation()
{
m_Timer = new Timer(OnTimer);
}
private void OnTimer(object unusedState)
{
lock (SyncRoot)
{
if (m_LastActionTime == null)
{
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
return;
}
TimeSpan timeSinceLastUpdate = DateTime.UtcNow - m_LastActionTime.Value;
if (timeSinceLastUpdate > TimeSpan.Zero)
{
// We are no idle yet.
m_Timer.Change(timeSinceLastUpdate, TimeSpan.Zero);
return;
}
m_LastActionTime = null;
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
}
if (m_IdleCallback != null)
{
m_IdleCallback();
}
}
// IdleNotifier implementation below
public void ActionOccured()
{
lock (SyncRoot)
{
m_LastActionTime = DateTime.UtcNow;
}
}
public IdleCallback Callback
{
set
{
lock (SyncRoot)
{
m_IdleCallback = value;
}
}
}
public TimeSpan IdleTimeSpanBeforeCallback
{
set
{
lock (SyncRoot)
{
m_IdleTimeSpanBeforeEvent = value;
// Run OnTimer immediately
m_Timer.Change(TimeSpan.Zero, TimeSpan.Zero);
}
}
}
}
There are many straight-forward performance improvements on this code.
If anyone would be intrested in my first thoughts on this just ask me.
I've actually had to build my own "Timing" class for an MMORPG I've made. It could keep track of over 100,000 "entities" that had timers for processing AI, and other tasks. Based on different actions that could be taken, I would have to momentarily delay an event.
Now, my timing class was completely hand written, so it won't be exactly what you're looking for. But something that you could do that would be similar to the solution I came up with is to do a sort of:
while (sleepyTime > 0)
{
int temp = sleepyTime;
sleepyTime = 0;
Thread.Sleep(temp);
}
// here's where your actual code is.
Then, you can make a "Delay" method that basically just ads to sleepyTime.