I have a task where I have to record a video in multiple segments. Let's take the scenario in this way, the user has started recording a video through a webcam and after 5 seconds it has stopped the recording, now we have the value of 5 seconds and our system will start recording the video again for the next 5 seconds and save it in a file. This process will run for multiple times(the value is already set by the user, let's say 3 times).
This is what I want to do in real.
And the Block of code that I shared is an illustration of the real task where code will run a task wait for some time, and repeat the process till it meets a condition which in our case is 3.
This piece of code is working fine but sometimes it skips the counting of seconds. By skipping I mean it will show 1 then lag for 2 seconds then will show 2 and 3 and so on.
I am afraid if I use this technique it might give me the wrong output and I need to be very precise with the recording time.
Is there any way to improve this piece of code?
Stopwatch sw;
private void btnStart_Click(object sender, EventArgs e)
{
sw = new Stopwatch();
timer1.Enabled = true;
sw.Start();
}
int counter = 1;
private void timer1_Tick(object sender, EventArgs e)
{
if (sw.Elapsed > TimeSpan.FromSeconds(4))
{
sw.Reset();
if (counter < 3)
{
sw.Start();
counter++;
}
else
{
sw.Reset();
timer1.Stop();
counter = 0;
MessageBox.Show("Counter has finished +"counter.ToString());
}
}
lblTime.Text = string.Format("{0:hh\\:mm\\:ss}", sw.Elapsed);
}
The question is a bit unclear and doesn't explain what needs to run. That matters.
One way to repeat a 5-second task 3 times would be to use a CancellationTokenSource that triggers after 5 seconds inside a loop. The worker code would have to check a CancellationToken to see when it needs to terminate :
async Task DoWorkAsync(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// The Block
}
}
async void btnStart_Clicked(object sender,EventArgs args)
{
var count=3;
var sw = new Stopwatch();
for (int i=0;i<count;i++)
{
sw.Restart();
using var cts=new CancellationTokenSource(TimeSpan.FromSeconds(5));
await DoWorkAsync(cts.Token);
lblTime.Text = $("{sw.Elapsed:hh\\:mm\\:ss}");
}
MessageBox.Show($"Counter has finished + {count}");
}
The UI can be updated after each await call, or through a Progress class. If the code block runs for a long time it can be made to run in the background with Task.Run that can be cancelled using the same token. If the block executes asynchronous operations, they could be cancelled as well :
async Task DoWorkAsync(CancellationToken token,IProgress<string> pg)
{
try
{
while(!token.IsCancellationRequested)
{
await Task.Run(()=>{
//Do Work 1
pg.Report("Done 1");
//Do Work 2
pg.Report("Done 2");
},token);
}
}
catch(OperationCanceledException)
{
pg.Report("Time's up!");
}
}
async void btnStart_Clicked(object sender,EventArgs args)
{
var pg=new Progress(DisplayProgress);
var count=3;
var sw = new Stopwatch();
for (int i=0;i<count;i++)
{
sw.Restart();
using var cts=new CancellationTokenSource(TimeSpan.FromSeconds(5));
await DoWorkAsync(cts.Token,pg);
lblTime.Text = $("{sw.Elapsed:hh\\:mm\\:ss}");
}
MessageBox.Show($"Counter has finished + {count}");
}
void DisplayProgress(string msg)
{
lblMessage.Text=msg;
}
In C# I have an example:
public async static Task TaskTest(int i)
{
await Task.Delay(1);
Console.WriteLine($"{i}. {DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadId:{Thread.CurrentThread.ManagedThreadId} Start");
int count = 1;
while (true)
{
DoSomeThing(count);
var stopWatch = new Stopwatch();
stopWatch.Start();
await Task.Delay(100);
stopWatch.Stop();
if (stopWatch.Elapsed.TotalMilliseconds > 200)
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Id:{count} Time:{DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadID:{Thread.CurrentThread.ManagedThreadId} Time Delay:{stopWatch.Elapsed.TotalMilliseconds }");
Console.ForegroundColor = ConsoleColor.White;
count++;
}
}
public async static Task DoSomeThing(int index)
{
await Task.Delay(1);
Task.Delay(1000).Wait();
}
private static void Main(string[] args)
{
int i = 1;
while (i < 2)
{
TaskTest(i);
Task.Delay(1).Wait();
i++;
}
Console.ReadKey();
}
Here is my result
Result
Id:8 Time:23:03:59 972 ThreadID:12 Time Delay:582.6348
Id:22 Time:23:04:01 974 ThreadID:14 Time Delay:552.7234000000001
Id:42 Time:23:04:04 967 ThreadID:8 Time Delay:907.3214
I don't know why Task sometimes delay more than 200 milliseconds.
Update:
Thank for all answer.
I update my code to use Thread and Thread.Sleep() and Task.Run(). I increase number of Threads run forever to 500. I tested in 30 minutes and 500 threads never sleep more than 200ms.
Do you think that is bad code?
Please leave a comment!
Thank you so much!
public static void TaskTest(object i)
{
Console.WriteLine($"{i} Start");
int count = 1;
while (true)
{
// Open Task to do work
Task.Run(() => { DoSomeThing(count); });
var stopWatch = new Stopwatch();
stopWatch.Start();
Thread.Sleep(100);
stopWatch.Stop();
if (stopWatch.Elapsed.TotalMilliseconds > 200)
{
Console.WriteLine($"Id:{count} Time:{DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadID:{Thread.CurrentThread.ManagedThreadId} Time Delay:{stopWatch.Elapsed.TotalMilliseconds }");
}
count++;
}
}
public static void DoSomeThing(int index)
{
Thread.Sleep(1000); // Time spent complete work
}
private static void Main(string[] args)
{
int i = 0;
while (i < 500)
{
// Open Thread for TaskTest
Thread tesThread = new Thread(TaskTest);
tesThread.IsBackground = true;
tesThread.Start(i);
i++;
}
Console.WriteLine("Finish init");
Console.ReadKey();
}
Task.Delay, like any other multi-threaded sleep function, yields the thread it's running on back to the system (or in the case of the thread pool, back to the thread pool scheduler), asking to be re-scheduled some time after the amount of time specified.
That is the only guarantee you have, that it will wait at least the amount specified. How long it will actually wait heavily depends on your thread pool load (you're delaying an awful lot of tasks there), general system load (there's thousands of threads at any given point in time to be scheduled on an average computer OS) and on your CPU&OS's capability to schedule threads quickly (in Windows, look at timeBeginPeriod).
Long story short, if precise timing matters to you, don't relinquish your thread.
I have a scenario to monitor the state of the ui test. If the test is running more than 30 mins, stop the test run and start with another test. Here is the code developed to simulate the same. I apologies if i am duplicating here.
Reference: execute mutiple object methods parallel
Here is the sample program that, developed in line with my requirement.I request experts to comment on my approach and suggest me the best of it.
<code>
namespace ParallelTasksExample
{
internal class Program
{
private static Stopwatch testMonitor;
private static int timeElapsed;
private static void Main(string[] args)
{
Parallel.Invoke(() => PrintNumber(), () => MonitorSequence());
}
private static void PrintNumber()
{
testMonitor = new Stopwatch();
testMonitor.Start();
for (int i = 0; i <= 10; i++)
{
System.Threading.Thread.Sleep(5000);
timeElapsed = testMonitor.Elapsed.Seconds;
Console.WriteLine("Running since :" + timeElapsed + " seconds");
}
}
private static void MonitorSequence()
{
while (timeElapsed < 25)
{
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Time Elapsed :" + timeElapsed + " seconds");
}
testMonitor.Stop();
testMonitor.Reset();
Console.WriteLine("Test has taken more then 25 seconds. Closing the current test sequence initiated.");
}
}
}
</code>
I am facing an issue, when the actual code developed based on the above example.
task 1 is completed and task 2 is in progress. Meanwhile task 1 is waiting for task2 to finish. How can we make both tasks are independent?
I've written a parellel.foreach, but the last iteration allways waits for execution before all other items have been processed, in this case, number 10 fires only when 1-9 are ready, tried it a couple of times, why is that and can i fix that?
here is my code:
class Program
{
public static void Main(string[] args)
{
int Min = 100;
int Max = 200;
Random randNum = new Random();
int[] test2 = Enumerable.Repeat(0, 10).Select(i => randNum.Next(Min, Max)).ToArray();
string[] result = test2.Select(x => x.ToString()).ToArray();
int count = 0;
var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };
Parallel.ForEach(result, options, rec =>
{
count++;
go(count);
});
Console.WriteLine("Ready!");
Console.ReadKey();
}
public static void go(int counter)
{
Console.WriteLine("START: " + counter.ToString());
Thread.Sleep(3500);
Console.WriteLine("END: " + counter.ToString());
}
}
EDIT
I ran the program for 20-30 times and it seems that a few times 10 is started before 9 ended. I think this happens in about 4 or 5 percent of the times. It's (working properly) happening some sort of random. because it works sometimes it feels a bit buggy, but not a big issue for the performance of my application which i'm building. You understand the above was a testcase, not a part of the actual project :)
This question already has answers here:
How to measure code performance in .NET?
(18 answers)
Closed 9 years ago.
What is the most exact way of seeing how long something, for example a method call, took in code?
The easiest and quickest I would guess is this:
DateTime start = DateTime.Now;
{
// Do some work
}
TimeSpan timeItTook = DateTime.Now - start;
But how exact is this? Are there better ways?
A better way is to use the Stopwatch class:
using System.Diagnostics;
// ...
Stopwatch sw = new Stopwatch();
sw.Start();
// ...
sw.Stop();
Console.WriteLine("Elapsed={0}",sw.Elapsed);
As others have said, Stopwatch is a good class to use here. You can wrap it in a helpful method:
public static TimeSpan Time(Action action)
{
Stopwatch stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.Elapsed;
}
(Note the use of Stopwatch.StartNew(). I prefer this to creating a Stopwatch and then calling Start() in terms of simplicity.) Obviously this incurs the hit of invoking a delegate, but in the vast majority of cases that won't be relevant. You'd then write:
TimeSpan time = StopwatchUtil.Time(() =>
{
// Do some work
});
You could even make an ITimer interface for this, with implementations of StopwatchTimer, CpuTimer etc where available.
As others said, Stopwatch should be the right tool for this. There can be few improvements made to it though, see this thread specifically: Benchmarking small code samples in C#, can this implementation be improved?.
I have seen some useful tips by Thomas Maierhofer here
Basically his code looks like:
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
//warm up
method();
var stopwatch = new Stopwatch()
for (int i = 0; i < repetitions; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
method();
stopwatch.Stop();
print stopwatch.Elapsed.TotalMilliseconds;
}
Another approach is to rely on Process.TotalProcessTime to measure how long the CPU has been kept busy running the very code/process, as shown here This can reflect more real scenario since no other process affects the measurement. It does something like:
var start = Process.GetCurrentProcess().TotalProcessorTime;
method();
var stop = Process.GetCurrentProcess().TotalProcessorTime;
print (end - begin).TotalMilliseconds;
A naked, detailed implementation of the samething can be found here.
I wrote a helper class to perform both in an easy to use manner:
public class Clock
{
interface IStopwatch
{
bool IsRunning { get; }
TimeSpan Elapsed { get; }
void Start();
void Stop();
void Reset();
}
class TimeWatch : IStopwatch
{
Stopwatch stopwatch = new Stopwatch();
public TimeSpan Elapsed
{
get { return stopwatch.Elapsed; }
}
public bool IsRunning
{
get { return stopwatch.IsRunning; }
}
public TimeWatch()
{
if (!Stopwatch.IsHighResolution)
throw new NotSupportedException("Your hardware doesn't support high resolution counter");
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
}
public void Start()
{
stopwatch.Start();
}
public void Stop()
{
stopwatch.Stop();
}
public void Reset()
{
stopwatch.Reset();
}
}
class CpuWatch : IStopwatch
{
TimeSpan startTime;
TimeSpan endTime;
bool isRunning;
public TimeSpan Elapsed
{
get
{
if (IsRunning)
throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");
return endTime - startTime;
}
}
public bool IsRunning
{
get { return isRunning; }
}
public void Start()
{
startTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = true;
}
public void Stop()
{
endTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = false;
}
public void Reset()
{
startTime = TimeSpan.Zero;
endTime = TimeSpan.Zero;
}
}
public static void BenchmarkTime(Action action, int iterations = 10000)
{
Benchmark<TimeWatch>(action, iterations);
}
static void Benchmark<T>(Action action, int iterations) where T : IStopwatch, new()
{
//clean Garbage
GC.Collect();
//wait for the finalizer queue to empty
GC.WaitForPendingFinalizers();
//clean Garbage
GC.Collect();
//warm up
action();
var stopwatch = new T();
var timings = new double[5];
for (int i = 0; i < timings.Length; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
action();
stopwatch.Stop();
timings[i] = stopwatch.Elapsed.TotalMilliseconds;
print timings[i];
}
print "normalized mean: " + timings.NormalizedMean().ToString();
}
public static void BenchmarkCpu(Action action, int iterations = 10000)
{
Benchmark<CpuWatch>(action, iterations);
}
}
Just call
Clock.BenchmarkTime(() =>
{
//code
}, 10000000);
or
Clock.BenchmarkCpu(() =>
{
//code
}, 10000000);
The last part of the Clock is the tricky part. If you want to display the final timing, its up to you to choose what sort of timing you want. I wrote an extension method NormalizedMean which gives you the mean of the read timings discarding the noise. I mean I calculate the the deviation of each timing from the actual mean, and then I discard the values which was farer (only the slower ones) from the mean of deviation (called absolute deviation; note that its not the often heard standard deviation), and finally return the mean of remaining values. This means, for instance, if timed values are { 1, 2, 3, 2, 100 } (in ms or whatever), it discards 100, and returns the mean of { 1, 2, 3, 2 } which is 2. Or if timings are { 240, 220, 200, 220, 220, 270 }, it discards 270, and returns the mean of { 240, 220, 200, 220, 220 } which is 220.
public static double NormalizedMean(this ICollection<double> values)
{
if (values.Count == 0)
return double.NaN;
var deviations = values.Deviations().ToArray();
var meanDeviation = deviations.Sum(t => Math.Abs(t.Item2)) / values.Count;
return deviations.Where(t => t.Item2 > 0 || Math.Abs(t.Item2) <= meanDeviation).Average(t => t.Item1);
}
public static IEnumerable<Tuple<double, double>> Deviations(this ICollection<double> values)
{
if (values.Count == 0)
yield break;
var avg = values.Average();
foreach (var d in values)
yield return Tuple.Create(d, avg - d);
}
Use the Stopwatch class
System.Diagnostics.Stopwatch is designed for this task.
Stopwatch is fine, but loop the work 10^6 times, then divide by 10^6.
You'll get a lot more precision.
I'm using this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myUrl);
System.Diagnostics.Stopwatch timer = new Stopwatch();
timer.Start();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
statusCode = response.StatusCode.ToString();
response.Close();
timer.Stop();