C#/.NET Timers and the Win32 Sleep function are both inexact - c#

For the following code:
The actual interval is always 1014.01 ms rather than 1000 ms ...
I've also tried to use System.Windows.Forms.Timer, System.Threading.Timer and the WinAPI Sleep(int) function in C++, but the additional increase of 14.01 ms always exists.
The System Clock of Windows 8 is exact, but both the .NET timers and the Sleep(int) function of Windows API are inexact.
public partial class Form1 : Form
{
private long ticks;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
// The actual interval is always 1014.01 ms ...
// I've also tried to use System.Windows.Forms.Timer, System.Threading.Timer
// and the WinAPI Sleep(int) function in C++, but the additional increase
// of 14.01 ms always exists.
timer.Elapsed += timer_Elapsed;
timer.Start();
ticks = System.DateTime.Now.Ticks;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
textBox1.Text = Math.Round((e.SignalTime.Ticks - ticks) / 10000.0, 2).ToString();
ticks = e.SignalTime.Ticks;
}
}
Update:
The native Sleep function (ReactOS):
// Call SleepEx with bAlertable = FALSE
VOID WINAPI Kernel32.Sleep(IN DWORD dwMilliseconds)
// Call NtDelayExecution with Alertable = bAlertable
// and DelayInterval.QuadPart = dwMilliseconds * -10,000
DWORD WINAPI Kernel32.SleepEx(IN DWORD dwMilliseconds, IN BOOL bAlertable)
// The syscall stub - call the kernel mode function NtDelayExecution directly
NTSTATUS NTAPI Ntdll.NtDelayExecution(IN BOOLEAN Alertable, IN PLARGE_INTEGER DelayInterval)
// Check for the access permissions of DelayInterval and then call KeDelayExecutionThread
NTSYSCALLAPI NTSTATUS NTAPI Ntoskrnl.NtDelayExecution(IN BOOLEAN Alertable, IN PLARGE_INTEGER DelayInterval)
// Core implement of the sleep/delay function
NTKERNELAPI NTSTATUS NTAPI Ntoskrnl.KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval OPTIONAL)
{
PKTIMER Timer;
PKWAIT_BLOCK TimerBlock;
PKTHREAD Thread = KeGetCurrentThread();
NTSTATUS WaitStatus;
BOOLEAN Swappable;
PLARGE_INTEGER OriginalDueTime;
LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
ULONG Hand = 0;
/* If this is a user-mode wait of 0 seconds, yield execution */
if (!(Interval->QuadPart) && (WaitMode != KernelMode))
{
/* Make sure the wait isn't alertable or interrupting an APC */
if (!(Alertable) && !(Thread->ApcState.UserApcPending))
{
/* Yield execution */
NtYieldExecution();
}
}
/* Setup the original time and timer/wait blocks */
OriginalDueTime = Interval;
Timer = &Thread->Timer;
TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
/* Check if the lock is already held */
if (!Thread->WaitNext) goto WaitStart;
/* Otherwise, we already have the lock, so initialize the wait */
Thread->WaitNext = FALSE;
KxDelayThreadWait();
/* Start wait loop */
for (;;)
{
/* Disable pre-emption */
Thread->Preempted = FALSE;
/* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
(Thread->WaitIrql < APC_LEVEL))
{
/* Unlock the dispatcher */
KiReleaseDispatcherLock(Thread->WaitIrql);
}
else
{
/* Check if we have to bail out due to an alerted state */
WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
if (WaitStatus != STATUS_WAIT_0) break;
/* Check if the timer expired */
InterruptTime.QuadPart = KeQueryInterruptTime();
if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
{
/* It did, so we don't need to wait */
goto NoWait;
}
/* It didn't, so activate it */
Timer->Header.Inserted = TRUE;
/* Handle Kernel Queues */
if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
/* Setup the wait information */
Thread->State = Waiting;
/* Add the thread to the wait list */
KiAddThreadToWaitList(Thread, Swappable);
/* Insert the timer and swap the thread */
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
KxInsertTimer(Timer, Hand);
WaitStatus = (NTSTATUS)KiSwapThread(Thread, KeGetCurrentPrcb());
/* Check if were swapped ok */
if (WaitStatus != STATUS_KERNEL_APC)
{
/* This is a good thing */
if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
/* Return Status */
return WaitStatus;
}
/* Recalculate due times */
Interval = KiRecalculateDueTime(OriginalDueTime,
&DueTime,
&NewDueTime);
}
WaitStart:
/* Setup a new wait */
Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
KxDelayThreadWait();
KiAcquireDispatcherLockAtDpcLevel();
}
/* We're done! */
KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
NoWait:
/* There was nothing to wait for. Did we have a wait interval? */
if (!Interval->QuadPart)
{
/* Unlock the dispatcher and do a yield */
KiReleaseDispatcherLock(Thread->WaitIrql);
return NtYieldExecution();
}
/* Unlock the dispatcher and adjust the quantum for a no-wait */
KiReleaseDispatcherLockFromDpcLevel();
KiAdjustQuantumThread(Thread);
return STATUS_SUCCESS;
}
// Note that the Windows API Sleep(0) will also call NtYieldExecution(), refer to
// the function Ntoskrnl.KeDelayExecutionThread above
The timeouts of the .NET Sleep(1), Sleep(0), Yield() and empty statement:
for (; ; )
{
Stopwatch sw = Stopwatch.StartNew();
// Thread.Sleep(1); // between 36000 and 39000
// Thread.Sleep(0); // 2 or 3
Thread.Yield(); // 1 or 2
// empty statement // always 0
Console.WriteLine(sw.ElapsedTicks);
sw.Restart();
}
The Stopwatch depends on the WinAPI functions QueryPerformanceCounter and QueryPerformanceFrequency:
static Stopwatch() {
bool succeeded = SafeNativeMethods.QueryPerformanceFrequency(out Frequency);
if(!succeeded) {
IsHighResolution = false;
Frequency = TicksPerSecond;
tickFrequency = 1;
}
else {
IsHighResolution = true;
tickFrequency = TicksPerSecond;
tickFrequency /= Frequency;
}
}
public static long GetTimestamp() {
if(IsHighResolution) {
long timestamp = 0;
SafeNativeMethods.QueryPerformanceCounter(out timestamp);
return timestamp;
}
else {
return DateTime.UtcNow.Ticks;
}
}
The Stopwatch is exact, but neither DateTime.UtcNow.Ticks nor Environment.TickCount is exact:
// Stopwatch is extremely exact without Thread.Sleep, always 1000.00 ms
// But the combination of Stopwatch + Thread.Sleep(1000) is inexact
// Stopwatch is very exact with Thread.Sleep + a spin check, always 1000 ms
thread = new Thread(() =>
{
var setText = new Action<long>(t => textBox1.Text
= Math.Round(t * 1000.0 / Stopwatch.Frequency, 2).ToString());
var sw = Stopwatch.StartNew();
for (; ; )
{
// In most cases 986 is exact enough, but very rarely it might produce
// a "1001", so use 985 here
Thread.Sleep(985);
while (sw.ElapsedTicks < Stopwatch.Frequency)
// Use Sleep(0) instead of Yield() or empty statement
Thread.Sleep(0);
// The actual interval is always 1000 ms instead of 1014.01 ms
// The Invoke method must be used since InvokeRequired is true
Invoke(setText, sw.ElapsedTicks);
sw.Restart();
}
});
thread.Start();
// DateTime.UtcNow.Ticks and DateTime.Now.Ticks are both inexact with
// Thread.Sleep + a spin check, still 1014.01 ms
thread = new Thread(() =>
{
var setText = new Action<long>(t => textBox1.Text
= Math.Round((t - ticks) / 10000.0, 2).ToString());
for (; ; )
{
Thread.Sleep(985);
while (DateTime.UtcNow.Ticks < ticks + 10000000)
Thread.Sleep(0);
var t = DateTime.UtcNow.Ticks;
Invoke(setText, t);
ticks = t;
}
});
thread.Start();
// Environment.TickCount is inexact with Thread.Sleep + a spin check,
// still 1014 ms (int value)
thread = new Thread(() =>
{
var setText = new Action<int>(t => textBox1.Text
= (t - msecs).ToString());
for (; ; )
{
Thread.Sleep(985);
while (Environment.TickCount < msecs + 1000)
Thread.Sleep(0);
var t = Environment.TickCount;
Invoke(setText, t);
msecs = t;
}
});
thread.Start();
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
thread.Abort();
}
References:
Source code of the ReactOS
Official Reference Source of the .NET 4.5 Update 1
The Shared Source CLI 2.0 (for native functions)
SwitchToThread/Thread.Yield vs. Thread.Sleep(0) vs. Thead.Sleep(1)
Thanks to everyone for help!

Sleep causes the OS to not schedule the thread until the time is up. Note that schedule != run.
Scheduling only adds the thread to a queue so it'll get run eventually, but not always immediately. For instance, if there's already a thread running, you still need to wait for its time slice to finish. If there are higher-priority threads in the queue, those could also run before it.
You should never count on Sleep() lasting exactly the amount of time you give it -- only at least that amount of time.
Timers basically operate the same way, but don't block a thread while they're waiting to be scheduled.
Also, you should be using Environment.TickCount or Stopwatch to measure elapsed time, not DateTime, which is affected by changes to the system time.

You can call timeBeginPeriod to tighten up the timer resolution. This also affects GetTickCount.
See Why does increasing timer resolution via timeBeginPeriod impact power consumption? for a discussion of why you might not want to do this (no idea whether this would be a concern in your situation of course).

why not use Stopwatch?
it's very precise
MSDN Stopwatch

If you need a Real-time Operating System, you need to look someplace else other than a Windows desktop OS.
For example: List of real-time operating systems

Your keyphrase is "multimedia timers".

You should not rely on Timer/Sleep interval for time sensitive calculations - it will never be exact. You can use Ticks instead or other high precision techniques. Resolution of Ticks is 1ms on Windows 7, according to this answer.
Also see here for more information: How to make an accurate decimal Timer?

The Windows OS is simply not designed for such things. This is a slight drawback to any OS that supports context switching. If you need very precise timings you'll need to use an embedded system or an OS that is designed to behave this way.
There are methods that will certainly improve the timing accuracy of whatever behavior you're trying to produce but it will be unreliable at best. At the end of the day the operating system is free to force a context switch which could delay your timer at any time.
Wikipedia has some more info on the subject: http://en.wikipedia.org/wiki/Real-time_operating_system

Related

Thread vs Parallel.For performance

I am struggling to understand the difference between threads and Parallel.For. I created two functions, one used Parallel.For other invoked threads. Invoking 10 threads would appear to be faster, can anyone please explain? Would threads use multiple processors available in the system (to get executed in parallel) or does it just do time slicing in reference to CLR?
public static bool ParallelProcess()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(0, 10, x =>
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(3000);
});
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(Thread1));
t.Start();
if (i == 9)
t.Join();
}
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
private static void Thread1()
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", 0,
Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(3000);
}
When called below methods, Parallel.For took twice time then threads.
Algo.ParallelThread(); //took 3 secs
Algo.ParallelProcess(); //took 6 secs
Parallel utilizes however many threads the underlying scheduler provides, which would be the minimum number of threadpool threads to start with.
The number of minimum threadpool threads is by default set to the number of processors. As time goes on and based on many different factors, e.g. all current threads being busy, the scheduler might decide to spawn more threads and go higher than the minimum count.
All of that is managed for you to stop unnecessary resource usage. Your second example circumvents all that by spawning threads manually. If you explicitly set the number of threadpool threads e.g. ThreadPool.SetMinThreads(100, 100), you'll see even the Parallel one takes 3 seconds as it immediately has more threads available to use.
You've got a bunch of things here that are going wrong.
(1) Don't use sw.Elapsed.Seconds this value is an int and (obviously) truncates the fractional part of the time. Worse though, if you have a process that takes 61 seconds to complete this will report 1 as it's like the second hand on a clock. You should instead use sw.Elapsed.TotalSeconds which reports as a double and it shows the total number of seconds regardless how many minutes or hours, etc.
(2) Parallel.For uses the thread-pool. This significantly reduces (or even eliminates) the overhead for creating threads. Each time you call new Thread(() => ...) you are allocating over 1MB of RAM and chewing up valuable resources before any processing can take place.
(3) You're artificially loading up the threads with Thread.Sleep(3000); and this means you are overshadowing the actual time it takes to create threads with a massive sleep.
(4) Parallel.For is, by default, limited by the number of cores on your CPU. So when you run 10 threads the work is being cut in to two steps - meaning that the Thread.Sleep(3000); is being run twice in series, hence the 6 seconds that it's running. The new Thread approach is running all of the threads in one go meaning that it takes just over 3 seconds, but again, the Thread.Sleep(3000); is swamping the thread start up time.
(5) You're also dealing with a CLR JIT issue. The first time you run your code the start-up costs are enormous. Let's change the code to remove the sleeps and to properly join the threads:
public static bool ParallelProcess()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(0, 10, x =>
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", x, Thread.CurrentThread.ManagedThreadId));
});
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.TotalMilliseconds));
return true;
}
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var threads = Enumerable.Range(0, 10).Select(x => new Thread(new ThreadStart(Thread1))).ToList();
foreach (var thread in threads) thread.Start();
foreach (var thread in threads) thread.Join();
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.TotalMilliseconds));
return true;
}
private static void Thread1()
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", 0, Thread.CurrentThread.ManagedThreadId));
}
Now, to get rid of the CLR/JIT start up time, let's run the code like this:
ParallelProcess();
ParallelThread();
ParallelProcess();
ParallelThread();
ParallelProcess();
ParallelThread();
The times we get are like this:
Time in secs 3.8617
Time in secs 4.7719
Time in secs 0.3633
Time in secs 1.6332
Time in secs 0.3551
Time in secs 1.6148
The starting run times are terrible compared to the second and third runs that are far more consistent.
The result is that running Parallel.For is 4 to 5 times faster than calling new Thread.
Your snippets are not equivalent. Here is a version of ParallelThread that would do the same as ParallelProcess but starting new threads:
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var threads = new Thread[10];
for (int i = 0; i < 10; i++)
{
int x = i;
threads[i] = new Thread(() => Thread1(x));
threads[i].Start();
}
for (int i = 0; i < 10; i++)
{
threads[i].Join();
}
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
private static void Thread1(int x)
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(3000);
}
Here, I am making sure to wait for all the threads. And also, I making sure to match the console output. Things that OP code does not do.
However, the time difference is still there.
Let me tell you what makes the difference, at least in my tests: the order. Run ParallelProcess before ParallelThread and they should both take 3 seconds to complete (ignoring the initial runs, which will take longer because of compilation). I cannot really explain it.
We could modify the above code futher to use the ThreadPool, and that did also result in ParallelProcess completing in 3 seconds (even though I did not modify that version). This is the version of ParallelThread with ThreadPool I came up with:
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var events = new ManualResetEvent[10];
for (int i = 0; i < 10; i++)
{
int x = i;
events[x] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem
(
_ =>
{
Thread1(x);
events[x].Set();
}
);
}
for (int i = 0; i < 10; i++)
{
events[i].WaitOne();
}
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
private static void Thread1(int x)
{
Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(3000);
}
Note: We could use WaitAll on the events, but that would fail on a STAThread.
You have Thread.Sleep(3000) which are the 3 seconds we see. Meaning that we are not really measuring the overhead of any of these methods.
So, I decided I want to study this futher, and to do it, I went up one order of magnitud (from 10 to 100) and removed the Console.WriteLine (which is introducing synchronization anyway).
This is my code listing:
void Main()
{
ParallelThread();
ParallelProcess();
}
public static bool ParallelProcess()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(0, 100, x =>
{
/*Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));*/
Thread.Sleep(3000);
});
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var events = new ManualResetEvent[100];
for (int i = 0; i < 100; i++)
{
int x = i;
events[x] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem
(
_ =>
{
Thread1(x);
events[x].Set();
}
);
}
for (int i = 0; i < 100; i++)
{
events[i].WaitOne();
}
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
private static void Thread1(int x)
{
/*Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));*/
Thread.Sleep(3000);
}
I am getting 6 seconds for ParallelThread and 9 seconds for ParallelProcess. This remains true even after reversing the order. Which makes me much more confident that this is a real measure of the overhead.
Adding ThreadPool.SetMinThreads(100, 100); bring the time back down to 3 seconds, for both ParallelThread (remember that this version is using the ThreadPool) and ParallelProcess. Meaning that this overhead comes from the thread pool. Now, I can go back to the version that spawns new threads (modified to spawn 100 and with Console.WriteLine commented):
public static bool ParallelThread()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var threads = new Thread[100];
for (int i = 0; i < 100; i++)
{
int x = i;
threads[i] = new Thread(() => Thread1(x));
threads[i].Start();
}
for (int i = 0; i < 100; i++)
{
threads[i].Join();
}
sw.Stop();
Console.WriteLine(string.Format("Time in secs {0}", sw.Elapsed.Seconds));
return true;
}
private static void Thread1(int x)
{
/*Console.WriteLine(string.Format("Printing {0} thread = {1}", x,
Thread.CurrentThread.ManagedThreadId));*/
Thread.Sleep(3000);
}
I get consistent 3 seconds from this version (meaning the time overhead is negligible, since, as I said earlier, Thread.Sleep(3000) is 3 seconds), however I want to note that it would be leaving more garbage to collect than using the ThreadPool or Parallel.For. On the other hand, using Parallel.For remains tied to the ThreadPool. By the way, if you want to degrade its performance, reducing the minimun number of threads is not enough, you got to degreade the maximun number of threads too (e.g. ThreadPool.SetMaxThreads(1, 1);).
All in all, please notice that Parallel.For is easier to use, and harder to wrong.
Invoking 10 threads would appear to be faster, can anyone please explain?
Spawning threads is fast. Although, it will leade to more garbage. Also, note that your test is not great.
Would threads use multiple processors available in the system (to get executed in parallel) or does it just do time slicing in reference to CLR?
Yes, they would. They map to the underlaying operating system threads, can be preempted by it, and will run in any core according to their affinity (see ProcessThread.ProcessorAffinity). To be clear, they are not fibers nor coroutines.
To put it in the simplest of the simplest terms, using Thread class guarantees to create a thread on the operating system level but using the Parallel.For the CLR thinks twice before spawning the OS-level threads. If it feels that it is a good time to create thread on OS-level, it goes ahead, otherwise it employs the available Thread pool. TPL is written to be optimized with a multi-core environment.

Using Tasks to perform delayed "timer-style" operations

I have an event in my application which mutates an object's state and refers that state to be reset 10 seconds later. But if that event is fired again within that those 10 seconds, the event does not change the state but simply resets the timer to zero.
To make it concise and easier to understand, Here is what my code does
I have an event that schedules tasks to be run 10 seconds later
If one task of a certain type is scheduled, and another request for the same comes in, the "execution time" for the existing future task is adjusted.
Currently I am doing it using a 'ConcurrentQueue' being manipulated in a Thread
public class ToDo
{
public DateTime Expires { get; set; }
public Action StuffToDo { get; set; }
}
Then my thread
public void MyWorkerThread(object parameters)
{
while (!<check if cancellation requested>)
{
ToDo stuff;
if (myConcurrentQueue.TryDequeue(out stuff))
{
if (DateTime.Now > stuff.Expires)
{
Task.StuffToDo.Invoke();
}
else
{
// queue it back if it is not time to execute it
//
myConcurrentQueue.Enqueue(stuff);
}
}
}
}
Here is my event handler that queues tasks
private ConcurrentDictionary<ToDo> _todoDictionary = new ConcurrentDictionary<ToDo>();
private ConcurrentQueue<ToDo> myConcurrentQueue = new ConcurrentQueue<ToDo>();
public void MyEventFired(MyEventArgs e)
{
ToDo todo = null;
if (_todoDictionary.ContainsKey(e.TaskType))
{
_todoDictionary.TryRemove(out todo);
if (DateTime.Now >= task.Expires)
{
todo = new ToDo();
todo.StuffToDo = new Action(() => { /* stuff here */ });
}
}
else
{
todo = new ToDo();
todo.StuffToDo = new Action(() => { /* stuff here */ });
}
todo.Expires = DateTime.Now + TimeSpan.FromSeconds(10.0);
_todoDictionary.Add(e.TaskType, todo);
myConcurrentQueue.Enqueue(todo);
}
Someone hinted to me that I could do all the above using TPL and I don't need a worker thread, I could just use 'Task.Delay'. I am still contemplating on how I will approach it. Any ideas will be appreciated.
Here is what I want to do
I am looking to rewrite the worker thread in terms of Task.Run and/or Task.Delay().ContinueWith sequences.
Your current MyWorkerThread code is a busy spinning loop. It drive on CPU core to 100%. You should hear your CPU fan spin up because of this.
Here's how I'd implement a resettable delay:
volatile int targetTicks = Environment.TickCount + (10 * 1000);
async Task WaitUntilTargetReachedAsync() {
while (true) {
var currentTicks = Environment.TickCount; //stabilize value
var targetTicksLocal = targetTicks; //volatile read, stabilize value
if (currentTicks >= targetTicksLocal) break; //Target reached.
await Task.Delay(TimeSpan.FromMilliseconds(targetTicksLocal - currentTicks));
}
}
WaitUntilTimeoutAsync() will complete exactly when targetTicks is reached. You can add time to targetTicks at any time and WaitUntilTimeoutAsync() will adjust. This way you can reset the timer to now plus 10 seconds:
targetTicks = Environment.TickCount + (10 * 1000);
Now that you have a task that completes exactly when you need it you can base your action on that:
targetTicks = Environment.TickCount + (10 * 1000); //Initial timer configuration.
await WaitUntilTimeoutAsync();
InvokeMyAction();

C# Timing Loop Rate Inaccuracies

I'm trying to create a method in C# whereby I can repeatedly perform an action (in my particular application it's sending a UDP packet) at a targeted rate. I know that timer inaccuracy in C# will prevent the output from being precisely at the target rate, but best effort is good enough. However, at higher rates, the timing seems to be completely off.
while (!token.IsCancellationRequested)
{
stopwatch.Restart();
Thread.Sleep(5); // Simulate process
int processTime = (int)stopwatch.ElapsedMilliseconds;
int waitTime = taskInterval - processTime;
Task.Delay(Math.Max(0, waitTime)).Wait();
}
See here for the full example console app.
When run, the FPS output of this test app shows around 44-46 Hz for a target of 60 Hz. However at lower rates (say 20 Hz), the output rate is much closer to the target. I can't understand why this would be the case. What is the problem with my code?
The problem is that Thread.Sleep (or Task.Delay) is not very accurate. Take a look at this: Accuracy of Task.Delay
One way to fix this is to a start the timer once, and then have a loop where you delay some ~15 ms in each iteration. Inside each iteration, you calculate how much times the operation should have been executed so far and you compare it with how many times you have run it so far. And you then run the operation enough times to catch up.
Here is some code sample:
private static void timerTask(CancellationToken token)
{
const int taskRateHz = 60;
var stopwatch = new Stopwatch();
stopwatch.Start();
int ran_so_far = 0;
while (!token.IsCancellationRequested)
{
Thread.Sleep(15);
int should_have_run =
stopwatch.ElapsedMilliseconds * taskRateHz / 1000;
int need_to_run_now = should_have_run - ran_so_far;
if(need_to_run_now > 0)
{
for(int i = 0; i < need_to_run_now; i++)
{
ExecuteTheOperationHere();
}
ran_so_far += need_to_run_now;
}
}
}
Please note that you want to use longs instead of ints if the process is to remain alive for a very long time.
If you replace this:
Task.Delay(Math.Max(0, waitTime)).Wait();
with this:
Thread.Sleep(Math.Max(0, waitTime));
You should get closer values on higher rates (why would you use Task.Delay(..).Wait() anyway?).

Measure Execution time of Parallel.For

I am using a Parallel.For loop to increase execution speed of a computation.
I would like to measure the approximate time left for the computation. Normally one simply has to measure the time it takes for each step and estimate the total time by multiplying the step time by the total number of steps.
e.g., If there are 100 steps and some step takes 5 seconds then one could except that the total time would be about 500 seconds. (one could average over several steps and continuously report to the user which is what I want to do).
The only way I can think to do this is by using an outer for loop that essentially resorts back to the original way by splitting up the parallel.for interval and measuring each one.
for(i;n;i += step)
Time(Parallel.For(i, i + step - 1, ...))
This isn't a very good way in general because either a few number of very long steps or a large number of short steps cause problems with timing.
Anyone have any ideas?
(Please realize I need a real time estimation of the time it is taking the parallel.for to complete and NOT the total time. I want to let the user know how much time is left in execution).
This method seems to be pretty effective. We can "linearize" the parallel for loop by simply having each parallel loop increment a counter:
Parallel.For(0, n, (i) => { Thread.Sleep(1000); Interlocked.Increment(ref cnt); });
(Note, thanks to Niclas, that ++ is not atomic and one must use lock or Interlocked.Increment)
Each loop, running in parallel, will increment cnt. The effect is that cnt is monotonically increasing to n, and cnt/n is the percentage of how much the for is complete. Since there is no contention for cnt, there are no concurrency issues and it is very fast and very perfectly accurate.
We can measure the percentage of completion of the parallel For loop at any time during the execution by simply computing cnt/n
The total computation time can be easily estimated by dividing the elapsed time since the start of the loop with the percentage the loop is at. These two quantities should have approximately the same rates of change when each loop takes approximately the same amount of time is relatively well behaved (can average out small fluctuation too).
Obviously the more unpredictable each task is, the more inaccurate the remaining computation time will be. This is to be expected and in general, there is no solution (which is why it's called an approximation). We can still get the elapsed computation time or percentage with complete accuracy.
The underlying assumption of any estimation of "time left" algorithms is each sub task takes approximately the same computation time (assuming one wants a linear result). For example, if we have a parallel approach where 99 tasks are very quick and 1 task is very slow, our estimation will be grossly inaccurate. Our counter will zip up to 99 pretty quick then sit on the last percentage until the slow task completes. We could linearly interpolate and do further estimation to get a smoother countdown but ultimately there is a breaking point.
The following code demonstrates how to measure the parallel for efficiently. Note the time at 100% is the true total execution time and can be used as a reference.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ParallelForTiming
{
class Program
{
static void Main(string[] args)
{
var sw = new Stopwatch();
var pct = 0.000001;
var iter = 20;
var time = 20 * 1000 / iter;
var p = new ParallelOptions(); p.MaxDegreeOfParallelism = 4;
var Done = false;
Parallel.Invoke(() =>
{
sw.Start();
Parallel.For(0, iter, p, (i) => { Thread.Sleep(time); lock(p) { pct += 1 / (double)iter; }});
sw.Stop();
Done = true;
}, () =>
{
while (!Done)
{
Console.WriteLine(Math.Round(pct*100,2) + " : " + ((pct < 0.1) ? "oo" : (sw.ElapsedMilliseconds / pct /1000.0).ToString()));
Thread.Sleep(2000);
}
}
);
Console.WriteLine(Math.Round(pct * 100, 2) + " : " + sw.ElapsedMilliseconds / pct / 1000.0);
Console.ReadKey();
}
}
}
This is almost impossible to answer.
First of all, it's not clear what all the steps do. Some steps may be I/O-intensive, or computationally intensive.
Furthermore, Parallel.For is a request -- you are not sure that your code will actually run in parallel. It depends on circumstances (availability of threads and memory) whether the code will actually run in parallel. Then if you have parallel code that relies on I/O, one thread will block the others while waiting for the I/O to complete. And you don't know what other processes are doing either.
This is what makes predicting how long something will take extremely error-prone and, actually, an exercise in futility.
This problem is a tough one to answer. The problems with timing that you refer to using very long steps or a large number of very short steps are likley related to that your loop will be working at the edges of what the parallel partitioner can handle.
Since the default partitioner is very dynamic and we know nothing about your actual problem there is no good answer that allows you to solve the problem at hand while still reaping the benefits of parallel execution with dynamic load balancing.
If it is very important to achive a reliable estimation of projected runtime perhaps you could set up a custom partitioner and then leverage your knowledge about the partioning to extrapolate timings from a few chunks on one thread.
Here's a possible solution to measure the average of all previously finished tasks. After each task finishes, an Action<T> is called where you could summarize all times and divide it by the total tasks finished. This is however just the current state and has no way to predict any future tasks / averages. (As others mentioned, this is quite difficult)
However: You'll have to measure if it fits for your problem because there is a possibility for lock contention on both the method level declared variables.
static void ComputeParallelForWithTLS()
{
var collection = new List<int>() { 1000, 2000, 3000, 4000 }; // values used as sleep parameter
var sync = new object();
TimeSpan averageTime = new TimeSpan();
int amountOfItemsDone = 0; // referenced by the TPL, increment it with lock / interlocked.increment
Parallel.For(0, collection.Count,
() => new TimeSpan(),
(i, loopState, tlData) =>
{
var sw = Stopwatch.StartNew();
DoWork(collection, i);
sw.Stop();
return sw.Elapsed;
},
threadLocalData => // Called each time a task finishes
{
lock (sync)
{
averageTime += threadLocalData; // add time used for this task to the total.
}
Interlocked.Increment(ref amountOfItemsDone); // increment the tasks done
Console.WriteLine(averageTime.TotalMilliseconds / amountOfItemsDone + ms.");
/*print out the average for all done tasks so far. For an estimation,
multiply with the remaining items.*/
});
}
static void DoWork(List<int> items, int current)
{
System.Threading.Thread.Sleep(items[current]);
}
I would propose having the method being executed at each step report when it is done. This is slightly tricky with thread safety of course, so that is something to remember when implementing. This will let you keep track of number of finished tasks out of the total, and also makes it (sort of) easy to know the time spent on each individual step, which is useful to remove outliers etc.
EDIT: Some code to demonstrate the idea
Parallel.For(startIdx, endIdx, idx => {
var sw = Stopwatch.StartNew();
DoCalculation(idx);
sw.Stop();
var dur = sw.Elapsed;
ReportFinished(idx, dur);
});
The key here is that ReportFinished will give you continuous information about number of finished tasks, and the duration of each of them. This enables you to do some better guesses about how long time remains by doing statistics on this data.
Here i wrote class that mesures time and speed
public static class Counter
{
private static long _seriesProcessedItems = 0;
private static long _totalProcessedItems = 0;
private static TimeSpan _totalTime = TimeSpan.Zero;
private static DateTime _operationStartTime;
private static object _lock = new object();
private static int _numberOfCurrentOperations = 0;
public static void StartAsyncOperation()
{
lock (_lock)
{
if (_numberOfCurrentOperations == 0)
{
_operationStartTime = DateTime.Now;
}
_numberOfCurrentOperations++;
}
}
public static void EndAsyncOperation(int itemsProcessed)
{
lock (_lock)
{
_numberOfCurrentOperations--;
if (_numberOfCurrentOperations < 0)
throw new InvalidOperationException("EndAsyncOperation without StartAsyncOperation");
_seriesProcessedItems +=itemsProcessed;
if (_numberOfCurrentOperations == 0)
{
_totalProcessedItems += _seriesProcessedItems;
_totalTime += DateTime.Now - _operationStartTime;
_seriesProcessedItems = 0;
}
}
}
public static double GetAvgSpeed()
{
if (_totalProcessedItems == 0) throw new InvalidOperationException("_totalProcessedItems is zero");
if (_totalProcessedItems == 0) throw new InvalidOperationException("_totalTime is zero");
return _totalProcessedItems / (double)_totalTime.TotalMilliseconds;
}
public static void Reset()
{
_totalProcessedItems = 0;
_totalTime = TimeSpan.Zero;
}
}
Example of usage and test:
static void Main(string[] args)
{
var st = Stopwatch.StartNew();
Parallel.For(0, 100, _ =>
{
Counter.StartAsyncOperation();
Thread.Sleep(100);
Counter.EndAsyncOperation(1);
});
st.Stop();
Console.WriteLine("Speed correct {0}", 100 / (double)st.ElapsedMilliseconds);
Console.WriteLine("Speed to test {0}", Counter.GetAvgSpeed());
}

How do you get list of running threads in C#?

I create dynamic threads in C# and I need to get the status of those running threads.
List<string>[] list;
list = dbConnect.Select();
for (int i = 0; i < list[0].Count; i++)
{
Thread th = new Thread(() =>{
sendMessage(list[0]['1']);
//calling callback function
});
th.Name = "SID"+i;
th.Start();
}
for (int i = 0; i < list[0].Count; i++)
{
// here how can i get list of running thread here.
}
How can you get list of running threads?
On Threads
I would avoid explicitly creating threads on your own.
It is much more preferable to use the ThreadPool.QueueUserWorkItem or if you do can use .Net 4.0 you get the much more powerful Task parallel library which also allows you to use a ThreadPool threads in a much more powerful way (Task.Factory.StartNew is worth a look)
What if we choose to go by the approach of explicitly creating threads?
Let's suppose that your list[0].Count returns 1000 items. Let's also assume that you are performing this on a high-end (at the time of this writing) 16core machine. The immediate effect is that we have 1000 threads competing for these limited resources (the 16 cores).
The larger the number of tasks and the longer each of them runs, the more time will be spent in context switching. In addition, creating threads is expensive, this overhead creating each thread explicitly could be avoided if an approach of reusing existing threads is used.
So while the initial intent of multithreading may be to increase speed, as we can see it can have quite the opposite effect.
How do we overcome 'over'-threading?
This is where the ThreadPool comes into play.
A thread pool is a collection of threads that can be used to perform a number of tasks in the background.
How do they work:
Once a thread in the pool completes its task, it is returned to a queue of waiting threads, where it can be reused. This reuse enables applications to avoid the cost of creating a new thread for each task.
Thread pools typically have a maximum number of threads. If all the threads are busy, additional tasks are placed in queue until they can be serviced as threads become available.
So we can see that by using a thread pool threads we are more efficient both
in terms of maximizing the actual work getting done. Since we are not over saturating the processors with threads, less time is spent switching between threads and more time actually executing the code that a thread is supposed to do.
Faster thread startup: Each threadpool thread is readily available as opposed to waiting until a new thread gets constructed.
in terms of minimising memory consumption, the threadpool will limit the number of threads to the threadpool size enqueuing any requests that are beyond the threadpool size limit. (see ThreadPool.GetMaxThreads). The primary reason behind this design choice, is of course so that we don't over-saturate the limited number of cores with too many thread requests keeping context switching to lower levels.
Too much Theory, let's put all this theory to the test!
Right, it's nice to know all this in theory, but let's put it to practice and see what
the numbers tell us, with a simplified crude version of the application that can give us a coarse indication of the difference in orders of magnitude. We will do a comparison between new Thread, ThreadPool and Task Parallel Library (TPL)
new Thread
static void Main(string[] args)
{
int itemCount = 1000;
Stopwatch stopwatch = new Stopwatch();
long initialMemoryFootPrint = GC.GetTotalMemory(true);
stopwatch.Start();
for (int i = 0; i < itemCount; i++)
{
int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable.
Thread thread = new Thread(() =>
{
// lets simulate something that takes a while
int k = 0;
while (true)
{
if (k++ > 100000)
break;
}
if ((iCopy + 1) % 200 == 0) // By the way, what does your sendMessage(list[0]['1']); mean? what is this '1'? if it is i you are not thread safe.
Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds);
});
thread.Name = "SID" + iCopy; // you can also use i here.
thread.Start();
}
Console.ReadKey();
Console.WriteLine(GC.GetTotalMemory(false) - initialMemoryFootPrint);
Console.ReadKey();
}
Result:
ThreadPool.EnqueueUserWorkItem
static void Main(string[] args)
{
int itemCount = 1000;
Stopwatch stopwatch = new Stopwatch();
long initialMemoryFootPrint = GC.GetTotalMemory(true);
stopwatch.Start();
for (int i = 0; i < itemCount; i++)
{
int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable.
ThreadPool.QueueUserWorkItem((w) =>
{
// lets simulate something that takes a while
int k = 0;
while (true)
{
if (k++ > 100000)
break;
}
if ((iCopy + 1) % 200 == 0)
Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds);
});
}
Console.ReadKey();
Console.WriteLine("Memory usage: " + (GC.GetTotalMemory(false) - initialMemoryFootPrint));
Console.ReadKey();
}
Result:
Task Parallel Library (TPL)
static void Main(string[] args)
{
int itemCount = 1000;
Stopwatch stopwatch = new Stopwatch();
long initialMemoryFootPrint = GC.GetTotalMemory(true);
stopwatch.Start();
for (int i = 0; i < itemCount; i++)
{
int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable.
Task.Factory.StartNew(() =>
{
// lets simulate something that takes a while
int k = 0;
while (true)
{
if (k++ > 100000)
break;
}
if ((iCopy + 1) % 200 == 0) // By the way, what does your sendMessage(list[0]['1']); mean? what is this '1'? if it is i you are not thread safe.
Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds);
});
}
Console.ReadKey();
Console.WriteLine("Memory usage: " + (GC.GetTotalMemory(false) - initialMemoryFootPrint));
Console.ReadKey();
}
Result:
So we can see that:
+--------+------------+------------+--------+
| | new Thread | ThreadPool | TPL |
+--------+------------+------------+--------+
| Time | 6749 | 228ms | 222ms |
| Memory | ≈300kb | ≈103kb | ≈123kb |
+--------+------------+------------+--------+
The above falls nicely inline to what we anticipated in theory. High memory for new Thread as well as slower overall performance when compared to ThreadPool. ThreadPool and TPL have equivalent performance with TPL having a slightly higher memory footprint than a pure thread pool but it's probably a price worth paying given the added flexibility Tasks provide (such as cancellation, waiting for completion querying status of task)
At this point, we have proven that using ThreadPool threads is the preferable option in terms of speed and memory.
Still, we have not answered your question. How to track the state of the threads running.
To answer your question
Given the insights we have gathered, this is how I would approach it:
List<string>[] list = listdbConnect.Select()
int itemCount = list[0].Count;
Task[] tasks = new Task[itemCount];
stopwatch.Start();
for (int i = 0; i < itemCount; i++)
{
tasks[i] = Task.Factory.StartNew(() =>
{
// NOTE: Do not use i in here as it is not thread safe to do so!
sendMessage(list[0]['1']);
//calling callback function
});
}
// if required you can wait for all tasks to complete
Task.WaitAll(tasks);
// or for any task you can check its state with properties such as:
tasks[1].IsCanceled
tasks[1].IsCompleted
tasks[1].IsFaulted
tasks[1].Status
As a final note, you can not use the variable i in your Thread.Start, since it would create a closure over a changing variable which would effectively be shared amongst all Threads. To get around this (assuming you need to access i), simply create a copy of the variable and pass the copy in, this would make one closure per thread which would make it thread safe.
Good luck!
Use Process.Threads:
var currentProcess = Process.GetCurrentProcess();
var threads = currentProcess.Threads;
Note: any threads owned by the current process will show up here, including those not explicitly created by you.
If you only want the threads that you created, well, why don't you just keep track of them when you create them?
Create a List<Thread> and store each new thread in your first for loop in it.
List<string>[] list;
List<Thread> threads = new List<Thread>();
list = dbConnect.Select();
for (int i = 0; i < list[0].Count; i++)
{
Thread th = new Thread(() =>{
sendMessage(list[0]['1']);
//calling callback function
});
th.Name = "SID"+i;
th.Start();
threads.add(th)
}
for (int i = 0; i < list[0].Count; i++)
{
threads[i].DoStuff()
}
However if you don't need i you can make the second loop a foreach instead of a for
As a side note, if your sendMessage function does not take very long to execute you should somthing lighter weight then a full Thread, use a ThreadPool.QueueUserWorkItem or if it is available to you, a Task
Process.GetCurrentProcess().Threads
This gives you a list of all threads running in the current process, but beware that there are threads other than those you started yourself.
Use Process.Threads to iterate through your threads.

Categories

Resources