Good day fellow developers,
I'm trying to create a Timing class in C# which can output the amount of time it takes to execute specific lines code. Here is the class that I developed so far (it is using the QueryPerformanceCounter):
class Timing
{
private long start;
private long stop;
private long frequency;
Decimal multiplier = new Decimal(1.0e9);
// Importing important DLL's that will be used
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
// Timing constructor
public Timing()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}
}
// Method for starting the counter
public void Start()
{
QueryPerformanceCounter(out start);
}
// Method for stopping the counter
public void Stop()
{
QueryPerformanceCounter(out stop);
}
// Returns the average time between iterations in nanoseconds
public double Duration(int iterations)
{
return ((((double)(stop - start) * (double)multiplier) / (double)frequency) / iterations);
}
// Get the elapsed time between the start and the stop function in nanoseconds
public double getElapsedTime()
{
return (((double)(stop - start) * (double)multiplier) / (double)frequency);
}
}
I wanted to perform a test to see if my Timing class would print out the same amount of time when executing the same line of code five times in a row:
static void Main(string[] args)
{
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
while (true) ;
}
public static void runCollectionTest(int iterations)
{
Timing timer = new Timing();
timer.Start();
ArrayList list = new ArrayList();
for (int i = 0; i < iterations; i++)
{
list.Add(i);
}
timer.Stop();
Console.WriteLine("Time elapsed: " + timer.getElapsedTime() / 1000000 + " milliseconds");
}
Here is the output of the code:
Time elapsed: 0,24631157341192 milliseconds
Time elapsed: 0,0486376114202896 milliseconds
Time elapsed: 0,0620241099763327 milliseconds
Time elapsed: 0,0589005936465893 milliseconds
Time elapsed: 0,088350890469884 milliseconds
I have no idea how the first time elapse and the second one can differ that much compared to the other results.
Related
I have an assignment where I am tasked to write a program in c# that will test out 5 different functions. I seem to be having problems because it seems like my output for the timing of these tests is wrong (i.e they are always returning 0ms back). Also, my unsynced threads are always returning back the full value of 5000 when they should not be doing that all the time, what am I doing wrong with test #2 and Am I stopping the timer in the wrong area? Threading is kind of messing with my mind at this point and I would like to have some clarification on the matter... Below is the spec and my code...
Test #1: Will be an increment (basic) to the value 5000.
Test #2: The main thread will create 10 threads that will increment the shared integer 500 times each. You will not use any synchronization to protect the updating of the shared integer. It is likely that the unsynchronized access to the shared integer will cause it to have an incorrect final value (<5000).
Test #3: The main thread will create 10 threads that will increment the shared integer 500 times each. You will protect the updating of the shared integer using a mutex.
Test #4: The main thread will create 10 threads that will increment the shared integer 500 times each. You will update the shared integer using the Increment method of the Interlocked class.
Test #5: The main thread will create 10 threads that will increment the shared integer 500 times each. You will protect the updating of the shared integer using a semaphore.
Each test will be timed using the Stopwatch class and the total time the test took will be written to the console.
Use Thread.Sleep() to simulate a random amount of processing time and assume the shared integer is being used at that time.
Random time should be a random value between 0 and 10ms.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace Lab3
{
class MainClass
{
public static int sharedVal = 0;
public static int y = 1;
static Stopwatch timer = new Stopwatch();
private static Mutex mutex = new Mutex();
private static Semaphore semaphore = new Semaphore(1, 1);
public static void Main(string[] args)
{
Console.WriteLine("***************** Lab 3 Thread/Synchronization Testing *****************" + "\n");
Console.WriteLine("Starting Test 1 (no Threads)...");
test1();
Console.WriteLine("***************** Lab 3 Thread/Synchronization Testing *****************" + "\n");
Console.WriteLine("Starting Test 2 (Threads without any synchronization)...");
test2(10);
Console.WriteLine("***************** Lab 3 Thread/Synchronization Testing *****************" + "\n");
Console.WriteLine("Starting Test 3 (Threads with a mutex)...");
test3(10);
Console.WriteLine("***************** Lab 3 Thread/Synchronization Testing *****************" + "\n");
Console.WriteLine("Starting Test 4 (Interlocked Methods)...");
test4(10);
Console.WriteLine("***************** Lab 3 Thread/Synchronization Testing *****************" + "\n");
Console.WriteLine("Starting Test 5 (Threads with a semaphore)...");
test5(10);
}
/*****************************************************************************/
public static void test1()
{
timer.Reset();
timer.Start();
intChanger(ref sharedVal, 5000,0);
Console.WriteLine("Test Complete");
timer.Stop();
Console.WriteLine("Shared Value: {0}, Total time: {1}ms ", sharedVal, timer.ElapsedMilliseconds);
clearSharedVal(ref sharedVal);
}
/*****************************************************************************/
public static void test2(int numOfThreads)
{
timer.Reset();
timer.Start();
threadCreate(numOfThreads);
Console.WriteLine("Test Complete");
Console.WriteLine("Shared Value: {0}, Total time: {1}ms ", sharedVal, timer.ElapsedMilliseconds);
clearSharedVal(ref sharedVal);
y++;
}
/*****************************************************************************/
public static void test3(int numOfThreads)
{
timer.Reset();
timer.Start();
threadCreate(numOfThreads);
Console.WriteLine("Test Complete");
Console.WriteLine("Shared Value: {0}, Total time: {1}ms ", sharedVal, timer.ElapsedMilliseconds);
clearSharedVal(ref sharedVal);
y++;
}
/*****************************************************************************/
public static void test4(int numOfThreads)
{
timer.Reset();
timer.Start();
threadCreate(numOfThreads);
Console.WriteLine("Test Complete");
Console.WriteLine("Shared Value: {0}, Total time: {1}ms ", sharedVal, timer.ElapsedMilliseconds);
clearSharedVal(ref sharedVal);
y++;
}
/*****************************************************************************/
public static void test5(int numOfThreads)
{
timer.Reset();
timer.Start();
threadCreate(numOfThreads);
Console.WriteLine("Test Complete");
Console.WriteLine("Shared Value: {0}, Total time: {1}ms ",sharedVal, timer.ElapsedMilliseconds);
clearSharedVal(ref sharedVal);
}
/*****************************************************************************/
public static void threadCreate(int n)
{
Thread[] threadArr = new Thread[n];
for (int i = 0; i < n; i++)
{
threadArr[i] = new Thread(new ThreadStart(WorkThreadFunction));
threadArr[i].Start();
}
//join for loop
for (int i = 0; i < n; i++)
{
threadArr[i].Join();
}
Console.WriteLine("All Threads have been joined");
timer.Stop();
}
/******************************************************************************/
public static void WorkThreadFunction()
{
switch (y) {
case 1:
intChanger(ref sharedVal, 500, 1);
break;
case 2:
intChanger(ref sharedVal, 500, 2);
break;
case 3:
intChanger(ref sharedVal, 500, 3);
break;
case 4:
intChanger(ref sharedVal, 500, 4);
break;
}
}
/*****************************************************************************/
public static void intChanger(ref int s, int n , int flag)
{
/*******************************************************************************
* Flag Explanation *
********************************************************************************
* int flag = 0 --> unsynchronized single thread adding to shared value *
* int flag = 1 --> unsynchronized threads adding to shared value *
* int flag = 2 --> synchronized using a mutex *
* int flag = 3 --> synchronized using Increment method of Interlocked class *
* int flag = 4 --> synchronized using semaphore *
********************************************************************************/
Random rand = new Random();
switch (flag)
{
case 0:
for (int i = 0; i < n; i++)
{
s++;
}
break;
case 1:
for (int i = 0; i < n; i++)
{
s++;
}
timer.Stop();
break;
case 2:
for (int i = 0; i < n; i++)
{
mutex.WaitOne();
Thread.Sleep(rand.Next(0, 10));
s++;
mutex.ReleaseMutex();
}
break;
case 3:
for (int i = 0; i < n; i++)
{
//Thread.Sleep(rand.Next(0, 10) * 1000);
Interlocked.Increment(ref s);
}
timer.Stop();
break;
case 4:
for (int i = 0; i < n; i++)
{
semaphore.WaitOne();
Thread.Sleep(rand.Next(0, 10));
s++;
semaphore.Release();
}
break;
}
}
/*****************************************************************************/
public static void clearSharedVal(ref int n)
{
n = 0;
}
}
}
Well, 5000 increments is a pretty simple task for a modern PC, so 0ms is expected for me. Try to increase a number of operations, or compare ElapsedTicks instead of ElapsedMilliseconds.
About #2. Creation of a new Thread is a heavy task, and the job itself is a light task. So, probably, to the time the next thread is ready to run, the previous one already finishes. They are running serially, not in parallel. You may again increase the number of operations, and use threadpool methods to run the job.
Edit:
Keep a note, that Thread.Sleep method works not as you may expect for very low delays (below 15-20ms): If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time.
I have setup an instance of Event Hub with 20 Throughput units and 32 partitions on Standard Tier. As per documentation, every throughput unit equates to 1 MB/second. So ideally I should be getting throughput of 20 MB/second or 1.2 GB/minute. The namespace has only one event hub and I am the only user. The event hub is set up in West US which is the option closest to where requests are sent from.
However, I see that it takes at least 10 minutes to 1.77GB of data. I am using async batch calls and packing each request to the 1 MB limit. I see a vast variance in time taken by SendBatchAsync call - it varies from 0.15 to 25 seconds.
Here is my code :
(Please note : I am constrained to use .Net Framework 4.5)
static EventHubClient eventHubClient;
static Dictionary<int, List<EventData>> events = new Dictionary<int, List<EventData>>();
static Dictionary<int, long> batchSizes = new Dictionary<int, long>();
static long threshold = (long)(1e6 - 1000);
static SemaphoreSlim concurrencySemaphore;
static int maxConcurrency = 1;
static void Main()
{
eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, eventHubName);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
using (concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
foreach (string record in GetRecords())
{
Tuple<int, EventData> currentEventDetails = GetEventData(record);
int partitionId = currentEventDetails.Item1;
EventData currentEvent = currentEventDetails.Item2;
BatchOrSendAsync(partitionId, currentEvent);
}
SendRemainingAsync();
}
stopWatch.Stop();
Console.WriteLine(string.Format("### total time taken = {0}", stopWatch.Elapsed.TotalSeconds.ToString()));
}
static async void BatchOrSendAsync(int partitionId, EventData currentEvent)
{
long batchSize = 0;
batchSizes.TryGetValue(partitionId, out batchSize);
long currentEventSize = currentEvent.SerializedSizeInBytes;
if( batchSize + currentEventSize > threshold)
{
List<EventData> eventsToSend = events[partitionId];
if (eventsToSend == null || eventsToSend.Count == 0)
{
if (currentEventSize > threshold)
throw new Exception("found event with size above threshold");
return;
}
concurrencySemaphore.Wait();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await eventHubClient.SendBatchAsync(eventsToSend);
stopWatch.Stop();
Console.WriteLine(stopWatch.Elapsed.TotalSeconds.ToString());
concurrencySemaphore.Release();
events[partitionId] = new List<EventData> { currentEvent };
batchSizes[partitionId] = currentEventSize;
}
else
{
if (!events.ContainsKey(partitionId))
{
events[partitionId] = new List<EventData>();
batchSizes[partitionId] = 0;
}
events[partitionId].Add(currentEvent);
batchSizes[partitionId] += currentEventSize;
}
}
static async void SendRemainingAsync()
{
foreach(int partitionId in events.Keys)
{
concurrencySemaphore.Wait();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await eventHubClient.SendBatchAsync(events[partitionId]);
stopWatch.Stop();
Console.WriteLine(stopWatch.Elapsed.TotalSeconds.ToString());
concurrencySemaphore.Release();
}
}
Note : increasing the maxConcurrency for the semaphore only degrades the overall time taken and the SendBatchAsync call starts erroring out when maxConcurrency is 10
What should I do to improve throughput?
I've created a multi task program. This program has around 20 main tasks and each of them calls some sub tasks to operate file I/Os. I wanted each main task to repeat periodically every 500ms, so I enterd the code Task.Delay(500).
The problem is Task.Delay delays a lot more than 500ms sometimes. There is a case it delays more than 3 seconds.
How can I fix it?
The original progam is so big that I created a sample program below.
(1) If Task.Delay is on, over-delay happens.
(2) If Thead.Sleep is on, over-delay doesn't happen.
ThreadPool.SetMinThreads() doesn't seem to resolve it.
Thanks.
class Program
{
const int DELAY_TIME = 500;
const int TASKS = 100;
const int WAITS = 100;
const int WARNING_THRESHOLD = 100;
static void Main(string[] args)
{
//ThreadPool.SetMinThreads(workerThreads: 200, completionPortThreads: 200);
Console.WriteLine("*** Start...");
Test();
Console.WriteLine("*** Done!");
Console.ReadKey();
}
private static void Test()
{
List<Task> tasks = new List<Task>();
for (int taskId = 0; taskId < TASKS; taskId++)
{
tasks.Add(DelaysAsync(taskId));
}
Task.WaitAll(tasks.ToArray());
}
static async Task DelaysAsync(int taskId)
{
await Task.Yield();
Stopwatch sw = new Stopwatch();
for (int i = 0; i < WAITS; i++)
{
sw.Reset();
sw.Start();
await Task.Delay(DELAY_TIME).ConfigureAwait(false); // (1)
//Thread.Sleep(DELAY_TIME); // (2)
sw.Stop();
Console.Write($"Task({taskId})_iter({i}) Elapsed={sw.ElapsedMilliseconds}");
if (sw.ElapsedMilliseconds > DELAY_TIME + WARNING_THRESHOLD)
{
Console.WriteLine(" *********** Too late!! ************");
}
else
{
Console.WriteLine();
}
}
}
}
I’ve run your test, with .NET 4.6.1 and VS 2017. Here on Xeon E3-1230 v3 CPU it never printed “Too late”, the Elapsed value was within 498-527 ms.
The Thread.Sleep version performed very similarly, 500-528ms per sleep, however the total execution time was much longer because the runtime refused to create 100 OS threads, that’s way too many, so less than 100 DelaysAsync functions ran in parallel. The debugger showed me there were 27 worker threads in Thread.Sleep version and only 9 worker threads in Task.Delay version.
I think you have other apps on your PC creating too many threads and consuming too much CPU. Windows tries to load balance threads evenly so when the whole system is CPU bound, more native threads = more CPU time and therefore less jitter.
If that’s your case and you want to prioritize your app in the scheduler, instead of using Thread.Sleep and more threads, raise the priority of your process.
It seems that I could find the answer. I changed the previous sample program like below. The main difference is using StopWatch or DateTime to measure time durations.
In StopWatch version, many delays happen.
In DateTime version, no or at least very little delays happen(s).
I guess that the cause is the contention of Timer that is used by both StopWatch and Task.Delay. I concluded that I should not use StopWatch and Task.Delay together.
Thank you.
class Program
{
const int DELAY_TIME = 500;
const int TASKS = 100;
const int WAITS = 100;
const int WARNING_THRESHOLD = 500;
static void Main(string[] args)
{
using (Process p = Process.GetCurrentProcess())
{
p.PriorityClass = ProcessPriorityClass.RealTime;
//ThreadPool.SetMinThreads(workerThreads: 200, completionPortThreads: 200);
int workerThreads;
int completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"{workerThreads}, {completionPortThreads}");
Console.WriteLine("*** Start...");
Test();
Console.WriteLine("*** Done!");
Console.ReadKey();
}
}
private static void Test()
{
int totalCount = 0;
List<Task<int>> tasks = new List<Task<int>>();
for (int taskId = 0; taskId < TASKS; taskId++)
{
//tasks.Add(DelaysWithStopWatchAsync(taskId)); // many delays
tasks.Add(DelaysWithDateTimeAsync(taskId)); // no delays
}
Task.WaitAll(tasks.ToArray());
foreach (var task in tasks)
{
totalCount += task.Result;
}
Console.WriteLine($"Total counts of deday = {totalCount}");
}
static async Task<int> DelaysWithStopWatchAsync(int taskId)
{
await Task.Yield();
int count = 0;
Stopwatch sw = new Stopwatch();
for (int i = 0; i < WAITS; i++)
{
sw.Reset();
sw.Start();
await Task.Delay(DELAY_TIME).ConfigureAwait(false); // (1)
//Thread.Sleep(DELAY_TIME); // (2)
sw.Stop();
Console.Write($"task({taskId})_iter({i}) elapsed={sw.ElapsedMilliseconds}");
if (sw.ElapsedMilliseconds > DELAY_TIME + WARNING_THRESHOLD)
{
Console.WriteLine($" *********** Too late!! ************");
count++;
}
else
{
Console.WriteLine();
}
}
return count;
}
static async Task<int> DelaysWithDateTimeAsync(int taskId)
{
await Task.Yield();
int count = 0;
for (int i = 0; i < WAITS; i++)
{
DateTime start = DateTime.Now;
await Task.Delay(DELAY_TIME).ConfigureAwait(false); // (1)
//Thread.Sleep(DELAY_TIME); // (2)
DateTime end = DateTime.Now;
int duration = (end - start).Milliseconds;
Console.Write($"Task({taskId})_iter({i}) Elapsed={duration}");
if (duration > DELAY_TIME + WARNING_THRESHOLD)
{
Console.WriteLine($" *********** Too late!! ************");
count++;
}
else
{
Console.WriteLine();
}
}
return count;
}
}
I understand that the point of asynchronous methods are not to improve performance but I am finding that the asynchronous methods on the StackExchange.Redis is taking alot longer than the sync methods.
public static async Task<bool> GetScoresFromSetAsync(int score, string name)
{
string redisConnection = ConfigurationManager.AppSettings["RedisAccount"].ToString();
ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(redisConnection);
IDatabase _cache = connection.GetDatabase();
List<string> scores = new List<string>();
var resultAsync = await _cache.SortedSetRangeByScoreAsync(name, score, score);
var result = _cache.SortedSetRangeByScore(name score, score);
return true;
}
The async call is taking about 5000 ms while the non async one is taking about 30ms on average. My redis is hosted on azure. Any thoughts?
Edit: I am talking about a single request here. The SortedSetRangeByScore api call is returning within 30 ms while the SortedSetRangeByScoreAsync api call is returning within 5000 ms.
Wondering how are you measuring the latency to compare? I tried measuring it with the following code and the time taken by SE.Redis for async vs sync came out to be pretty close. I hope this helps.
My client code is running on a Azure Iaas VM and connecting to a Azure Redis Cache in the same region.
Measuring sync vs async for sorted set length 10000, iterations 10000
10000 sync calls completed in average 1.41190622 ms
10000 async calls completed in average 1.43989741 ms
Measuring sync vs async for sorted set length 100000, iterations 1
1 sync calls completed in average 0.9513 ms
1 async calls completed in average 1.1436 ms
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace RedisLatency
{
class Program
{
private const string host = "myazurecache.redis.cache.windows.net";
private const string password = "password";
private static int sortedsetlength;
private static int iterations;
private static IDatabase _cache;
static void Main(string[] args)
{
sortedsetlength = Int32.Parse(args[0]);
iterations = Int32.Parse(args[1]);
CreateMultiplexer(host,password);
PopulateTestData();
RunTestSync();
RunTestAsync();
}
private static void CreateMultiplexer(string host, string password)
{
Console.WriteLine("Measuring sync vs async for sorted set length {0}, iteration {1}", sortedsetlength,iterations);
ConfigurationOptions configoptions = new ConfigurationOptions();
configoptions.EndPoints.Add(host);
configoptions.Password = password;
configoptions.Ssl = true;
ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(configoptions);
_cache = connection.GetDatabase();
}
private static void PopulateTestData()
{
for (int i = 0; i < sortedsetlength; i++)
{
_cache.SortedSetAdd("testsorted", "user" + i, i);
}
}
static void RunTestSync()
{
for (int warmup = 0; warmup < 100; warmup++)
{
MeasureSync();
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations;i++ )
{
MeasureSync();
}
sw.Stop();
Console.WriteLine("{0} sync calls completed in average {1} ms", iterations, sw.Elapsed.TotalMilliseconds/iterations);
}
async static void RunTestAsync()
{
//warm up
for (int warmup = 0; warmup < 100; warmup++)
{
MeasureAsync().Wait();
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
MeasureAsync().Wait();
}
sw.Stop();
Console.WriteLine("{0} async calls completed in average {1} ms", iterations, sw.Elapsed.TotalMilliseconds/iterations);
}
static public void MeasureSync()
{
var result = _cache.SortedSetRangeByScore("testset", 1.0, sortedsetlength / 1.0);
}
async static public Task MeasureAsync()
{
var result = await _cache.SortedSetRangeByScoreAsync("testset", 1.0, sortedsetlength / 1.0);
}
}
}
im trying to create a timer to "tick" and created this timer with a little google help.
It works perfectly in console, but when i added it in a website, it seems my computer is running at full capasity, and the site is loading slowly and not function properly.
Can i use this or do i need to start over?
namespace ticket
{
class Program
{
public static int counttick = 0;
public static int ticks = 0;
static void LoopingFunction()
{
while (counttick <= 20)
{
int dwStartTime = System.Environment.TickCount;
while (true)
{
if (System.Environment.TickCount - dwStartTime > 1000) break; //1000 milliseconds
}
counttick++;
if (counttick == 20)
{
ticks++;
counttick = 0;
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
Label2.Text = "Ticks: " + Convert.ToString(ticks);
LoopingFunction();
}
}
}`
Remove:
while (true)
{
if (System.Environment.TickCount - dwStartTime > 1000) break; //1000 milliseconds
}
And use:
System.Threading.Sleep(1000);
Try System.Threading.Timer class.
In web applications i don't recommend using static variables, because you really never know when you IIS will recycle the app pool and you static varitable will become 0. rather you should try something to persistence storage. and use to Try System.Threading.Timer class to update the value in may be a Database table or some file.
Regards.
I'll just give another approach. I needed a similar tick loop that runs at about 25 frames per second. I have a class called ApplicationLoop which, when constructed starts a thread. That thread is my application loop. (Hence the obvious class name.)
So I have a few constants, to determine my frame rate, and a frame-skip fallback value. Basically, when a task takes more time than 40ms (1000 / 25 = 40), I loop through all the tasks again to "catch-up". But I only do this a number of times.
private const int MAX_FRAMESKIP = 5;
private const int UPDATE_SKIP_TICKS = 1000 / UPDATE_TICKS_PER_SECOND;
private const int UPDATE_TICKS_PER_SECOND = 25;
My thread function:
private void UpdateLoop()
{
ulong ticks = 0UL;
_isRunning = true;
var next = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
while (_isRunning)
{
var now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
int loops = 0;
while ((now > next) && _isRunning && (loops < MAX_FRAMESKIP))
{
ProcessTasks(ticks);
next += UPDATE_SKIP_TICKS;
loops++;
ticks++;
}
AccurateSleep(1);
}
}
My class contains a Subscribe() function which takes a delegate. I store that callback into a List and the ProcessTasks() function calls each subscribed function.
You can replace the AccurateSleep() function with a simple Thread.Sleep(1) call, but be aware that the default time-slice for a sleep is about 15ms.
[DllImport("winmm.dll")]
private static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")]
private static extern uint timeEndPeriod(uint period);
private static void AccurateSleep(int sleep)
{
timeBeginPeriod(1);
Thread.Sleep(sleep);
timeEndPeriod(1);
}