It seems like there are a lot of ways to calculate time spans in c#. I am wondering which one is fastest and by that I simply means requires the least amount of processing. Let me throw out an example to illustrate exactly what I am trying to do.
private const int timeBetweenEvents = 250; //delay ms
DateTime nextUpdate = DateTime.Now.Add(new TimeSpan(0, 0, 0, timeBetweenEvents));
...
while(true)
{
if (DateTime.Now > nextUpdate)
{
// do something
nextUpdate = DateTime.Now.Add(new TimeSpan(0, 0, 0, timeBetweenEvents));
}
// ...
// do some other stuff
// ...
}
another option...
private const int timeBetweenEvents = 250; //delay ms
TimeSpan nextUpdate = DateTime.Now.TimeOfDay.Add(new TimeSpan(0,0,0,timeBetweenEvents));
...
while(true)
{
if (DateTime.Now.TimeOfDay > nextUpdate)
{
// do something
nextUpdate = DateTime.Now.TimeOfDay.Add(new TimeSpan(0, 0, 0, timeBetweenEvents));
}
// ...
// do some other stuff
// ...
}
I have also seen similar things by doing subtractions using System.Environment.TickCount. So what is the bst way to do this?
DateTime, Environment.TickCount and Thread.Sleep have a resolution of 30ms - which may cause problems. Stopwatch doesn't have this problem (on platforms that support it, i.e. pretty much any machine today) - plus the code is also a little shorter (the fastest code is code that is never executed) and clearer.
const long millisecondsBetweenEvents = 250;
var sw = new Stopwatch();
sw.Start();
while(true)
{
if (sw.ElapsedMilliseconds > millisecondsBetweenEvents)
{
// do something
sw.Restart();
}
}
If you're looking for performance, at the very least cache the value of DateTime.Now outside of the loop. I remember reading it can be a relatively expensive function to call.
I would use a Timer
A StopWatch will have better precision.
Related
This question already has answers here:
How do you add a timer to a C# console application
(12 answers)
Closed 5 years ago.
I have a while loop that runs for a long number of times. I have some writelines in there that serve as debug statements. I use a verbosity flag to determine when I want to see those statements written to the console. Is there a way I can also specify to output every x milliseconds , instead of all the time.
while
{
//logic here
if(verboseMode)
Console.Writeline("some status message")
}
With the way the code is right now, the writeline executes all the time when verboseMode is set to true. What id like to do is output the line if verboseMode is set to true and the last time I output something it was x milliseconds ago
You can use a Timer or just keep track of when you last wrote output. The Timer is probably preferable because your main functionality won't block it from running whereas the other will.
I used random just to simulate the fact that the while loop won't always run in the same amount of time to demonstrate the difference between the approaches.
var r = new Random();
var t = new System.Timers.Timer() { Interval = 1500 };
t.Elapsed += (s, e) =>
Console.WriteLine(DateTime.Now.TimeOfDay);
t.Start();
while (true)
{
Thread.Sleep(r.Next(500, 1000));
Console.WriteLine("doing stuff");
}
var r = new Random();
var prev = DateTime.Now;
var interval = 1500;
while (true)
{
Thread.Sleep(r.Next(500, 1000));
Console.WriteLine("doing stuff");
var now = DateTime.Now;
if (prev.AddMilliseconds(interval) >= now)
{
prev = DateTime.Now;
Console.WriteLine(DateTime.Now.TimeOfDay);
}
}
What you ask for is rate limiting. I wrote this code originally for Multithreading, but it should get you the idea:
integer interval = 20;
DateTime dueTime = DateTime.Now.AddMillisconds(interval);
while(true){
if(DateTime.Now >= dueTime){
//insert code here
//Update next dueTime
dueTime = DateTime.Now.AddMillisconds(interval);
}
else{
//Just yield to not tax out the CPU
Thread.Sleep(1);
}
}
Note that DateTime is not nearly as accurate as the type is precise. Often the smalest difference tracked is 16 ms or so. But then again, 16 ms would get you around 60 changes per seconds, wich is propably to top adivseable writing/updating speed anyway.
If you don't care much about precision you can get away with running the while loop on a different thread using Task.Run:
var source = new CancellationTokenSource();
var task = Task.Run(() =>
{
while (!source.Token.IsCancellationRequested)
{
DoSomething();
await Task.Delay(500, source.Token);
}
});
// If you want to cancel the loop
source.Cancel();
task.Wait(); // or 'await task;' if you're in an async method
I have to update some data every 1 hour in a Thread. I put the Method-checker into a new Thread
if ((time_now - last_update) < 3600)
Thread.Sleep(3600 * 1000);
But I feel like this isn't correct. Maybe there is an elegant and inexpensive way to check for updates every hour without Thread.Sleep in C#?
How about running your pulling method every fixed time:
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromHours(1);
var timer = new System.Threading.Timer((e) =>
{
YourPullingMethod();
}, null, startTimeSpan, periodTimeSpan);
sleep should not be use. It is unreliable and can not be canceled; it is also blocking
you can do something like the following.
object waitTimeOut = new object();
lock (waitTimeOut)
{
Monitor.Wait(waitTimeOut, TimeSpan.FromMilliseconds(3600 * 1000));
}
or
TimeSpan ts = TimeSpan.FromMilliseconds(3600 * 1000);
t.Wait(ts)
Or with the low frequence you the other comments are good about using a cron job; and would be much more suitable to what you are doing
Have a look at the System.Threading.Timer class (or the other timers, use the one that is best suited for you).
I am start my operation and one of the argument my command line application get is Number that represent how much time my operation need to run.
int duration = int.Parse(args[0]) // run my operation for this time in minutes
This is what i have try (not working):
...
DateTime start = DateTime.Now;
// check whether this time in minutes passed
if (start.Minute > duration )
break;
EDIT: use UtcNow
void DoWork(int durationInMinutes)
{
DateTime startTime = DateTime.UtcNow;
TimeSpan breakDuration = TimeSpan.FromMinutes(durationInMinutes);
// option 1
while (DateTime.UtcNow - startTime < breakDuration)
{
// do some work
}
// option 2
while (true)
{
// do some work
if (DateTime.UtcNow - startTime > breakDuration)
break;
}
}
For this you can use StopWatch by defining
StopWatch watch = new StopWatch();
watch.Start();
and where ever ur code finishes running write
watch.Stop();
By using stopwach you can see you are running time of your application in detail. Of course if I am correct to understand you.
I want to run a function periodically every 1 second, so after 10 seconds it is executed 10 times.
The simplest approach is using a loop like this :
while(true)
{
Thread.Sleep(1000);
function();
}
But the main problem with this approach is that it will not provide any periodic guarantees.
I mean if it takes 0.1 seconds to run function() the executions time of the function will be like this :
0, 1.1 , 2.2, 3.3, 4.4 , ...
As I remember, in real time language ADA we have a function sleep-until(#time). Now I'm looking for an alternative in C#.
Any sample code will be appreicated.
System.Threading.Timer timer = new System.Threading.Timer(ThreadFunc, null, 0, 1000);
private static void ThreadFunc(object state)
{
//Do work in here.
}
See MSDN for more info.
You can use Stopwatch to measure the time. I would also use a For-Loop instead.
var sw = new System.Diagnostics.Stopwatch();
var timeForOne = TimeSpan.FromSeconds(1);
var count = 10;
for(int i = 0; i < count; i++)
{
sw.Restart();
function();
sw.Stop();
int rest = (timeForOne - sw.Elapsed).Milliseconds;
if (rest > 0)
System.Threading.Thread.Sleep(rest);
}
To invoke something after specific interval of time you should use Timer class.
Here is the Tutorial
Is it bad practice to use such while loop?
Maybe it is better to use Stopwatch, or maybe this solution has some pitfalls?
public void DoWork()
{
//do some preparation
DateTime startTime = DateTime.Now;
int rowsCount = 0;
int finalCount = getFinalCount();
do
{
Thread.Sleep(1000);
rowsCount = getRowsCount(); // gets rows count from database, rows are added by external app.
} while (rowsCount < finalCount && DateTime.Now - startTime < TimeSpan.FromMinutes(10));
}
I saw this article Implement C# Generic Timeout,
but it is too complex to use in simple scenarios - you need to think about sync of threads, is it proper to abort them or not and so on.
As I understand it, you want your method to do some work until it's done or until some period of time has elapsed? I would use a Stopwatch for that, and check the elapsed time in a loop:
void DoWork()
{
// we'll stop after 10 minutes
TimeSpan maxDuration = TimeSpan.FromMinutes(10);
Stopwatch sw = Stopwatch.StartNew();
DoneWithWork = false;
while (sw.Elapsed < maxDuration && !DoneWithWork)
{
// do some work
// if all the work is completed, set DoneWithWork to True
}
// Either we finished the work or we ran out of time.
}
It is better to use the System.Timers.Timer class.