Exact time measurement for performance testing [duplicate] - c#

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();

Related

C# Limit Calls Per Second

I am calling a service that only allows 10 calls per second. I am using Stopwatch and Thread.Sleep to limit my calls. Are these the correct tools for this job, or should I be using Timers or some other tool.
public void SomeFunction() {
Stopwatch stopwatch = new Stopwatch();
int numCallsThisSecond = 0;
foreach(MyEvent changedEvent in changedEvents) {
stopwatch.Start();
service.ChangeEvent(changedEvent);
numCallsThisSecond += 1;
stopwatch.Stop();
if(numCallsThisSecond==10 && stopwatch.ElapsedMilliseconds<=1000)
Thread.Sleep((int)(1100-stopwatch.ElapsedMilliseconds));
if(stopwatch.ElapsedMilliseconds>1000) {
stopwatch.Reset();
numCallsThisSecond = 0;
}
}
}
Thank you in advance for any help!
As you already know it can be 10 calls / sec. Code can be simple as follows :
public void SomeFunction()
{
foreach(MyEvent changedEvent in changedEvents)
{
service.ChangeEvent(changedEvent);
Thread.Sleep(100);//you already know it can be only 10 calls / sec
}
}
Edit :
Ok got it, please see if following alternative will be helpful, it only allows 10 or less calls per second depending on how its performing :
public void SomeFunction()
{
DateTime lastRunTime = DateTime.MinValue;
foreach(MyEvent changedEvent in changedEvents)
{
lastRunTime = DateTime.Now;
for (int index = 0; index < 10; index++)
{
if (lastRunTime.Second == DateTime.Now.Second)
{
service.ChangeEvent(changedEvent);
}
else
{
break;//it took longer than 1 sec for 10 calls, so break for next second
}
}
}
}

Time duration,time start and time end of a method in C#

how can I record the time duration, time start and time end of a method once it was executed using c#?
for example, I click a button and it will do something. Once it start, I'll get the start time, then when the execution is done, I'll get the time end and also the duration of time it take to finish.
You can use the Stopwatch, which resides in System.Diagnostics namespace.
This has the features of a normal stopwatch, with Start, Stop, Reset, ElapsedMilliseconds and so forth.
This is great for measuring a specific code block or method. You do however state that you want both start and end time in addition to the duration of execution. You could create a custom stopwatch by inheriting the Stopwatch class and extending it with a couple of DateTime properties.
public class CustomStopwatch : Stopwatch
{
public DateTime? StartAt { get; private set; }
public DateTime? EndAt { get; private set; }
public void Start()
{
StartAt = DateTime.Now;
base.Start();
}
public void Stop()
{
EndAt = DateTime.Now;
base.Stop();
}
public void Reset()
{
StartAt = null;
EndAt = null;
base.Reset();
}
public void Restart()
{
StartAt = DateTime.Now;
EndAt = null;
base.Restart();
}
}
And use it like this:
CustomStopwatch sw = new CustomStopwatch();
sw.Start();
Thread.Sleep(2342); // just to use some time, logic would be in here somewhere.
sw.Stop();
Console.WriteLine("Stopwatch elapsed: {0}, StartAt: {1}, EndAt: {2}", sw.ElapsedMilliseconds, sw.StartAt.Value, sw.EndAt.Value);
You can use System.Diagnostics.Stopwatch class to achieve this. see the sample
// Create new stopwatch
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
// Begin timing
stopwatch.Start();
// Tasks performed by method
// Stop timing
stopwatch.Stop();
Console.WriteLine("Time taken : {0}", stopwatch.Elapsed);
I've done it by doing this
var watch = System.Diagnostics.Stopwatch.StartNew();
string startTime = DateTime.Now.ToLongTimeString();
//Insert Code Here
watch.Stop();
string timeEnd = DateTime.Now.ToLongTimeString();
//Time Format
string[] hours = watch.Elapsed.TotalHours.ToString().Split('.');
string[] minutes = watch.Elapsed.TotalMinutes.ToString().Split('.');
string[] seconds = watch.Elapsed.TotalSeconds.ToString().Split('.');
string[] milliseconds = watch.Elapsed.TotalMilliseconds.ToString().Split('.');
MessageBox.Show(hours[0].ToString() + ":" + minutes[0].ToString() + ":" + seconds[0].ToString() + "." + milliseconds[0].ToString());
First, you need to create a stopwatch object.
private readonly Stopwatch stopwatch = new Stopwatch();
Then, your method:
public void MyMethod()
{
stopwatch.Start();
// Any other code here.
stopwatch.Stop();
//returns longs
long runningTimeInMs = stopwatch.ElapsedMilliseconds;
}

More efficient way of implementing a countdown timer/clock?

I'm writing a small lap counter for slot car races as a little home project. I want to implement a countdown timer, which I've done with the following as a test:
private Thread countdownThread;
private delegate void UpdateTimer(string update);
UpdateTimer ut;
public LapCounterForm()
{
InitializeComponent();
//...
ut += updateTimer;
countdownThread = new Thread(new ThreadStart(startCountdown));
}
private void startCountdown()
{
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
System.Diagnostics.Stopwatch stopwatch = new Stopwatch();
long time = 0;
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds <= 5000)
{
time = 5000 - stopwatch.ElapsedMilliseconds;
TimeSpan ts = TimeSpan.FromMilliseconds(time);
ut(ts.Minutes.ToString().PadLeft(2, '0') + ":" + ts.Seconds.ToString().PadLeft(2, '0') + ":" + ts.Milliseconds.ToString().PadLeft(3, '0'));
}
}
private void updateTimer(string text)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<String>(ut), new object[] { text });
}
else
{
lblCountdownClock.Text = text;
}
}
When I start my thread, it works. I get my 5 second countdown like I want, but I can see that I'm using a lot of CPU in the process (12% of my 8 thread i7 2600k).
I figure I can reduce this load a lot by only updating the UI every 10 milliseconds instead of every millisecond, but I have no idea how to do such, other than using if(time % 10 == 0) before making the TimeSpan and updating the UI but I suspect that will be just as inefficient thanks to the while loop.
Am I reinventing the wheel? I'd like my timer to be as accurate as possible (at least for the slot car lap time recordings, perhaps the UI does not need to be updated so often).
EDIT: I tried commenting out the actual string manipulation and UI update as suggested in the comments. Now when I start my thread my entire UI hangs until the thread exits and I still get 12% CPU usage. I suspect that while loop is eating up a lot of CPU time.
Update: I went with the multimedia timer (here) posted by Kohanz as well as Daniel's answer. I no longer use another thread at all, I just make one of those timer objects and have a tick event handler calculating the time between clicking the start button and the tick event. I can even set the period for my ticks to 1ms so I get my cool looking countdown, and it's apparently using 0% CPU :) I'm quite happy with this.
Dont, just DONT go down this road. You are completely thinking of this in the wrong way. You are basically forcing your thread to freeze for no benefit.
Basically any game works this way: you have an update loop, and whenever that triggers you do neccessary stuff. So for instance if you want to know how much time, you ask some kind of "timer" how much has passed since something happened
Here's a much better way to handle this:
class MyStopwatch {
private DateTime _startTime;
private DateTime _stopTime;
public void start() {
_running = true;
_startTime = DateTime.Now;
}
public void stop() {
_stopTime = DateTime.Now;
_running = false;
}
public double getTimePassed() {
if(_running) {
return (DateTime.Now - _startTime).TotalMilliseconds;
} else {
return (_stopTime - _startTime).TotalMilliseconds;
}
}
}
A bit after the fact, but this shows a way in which you might achieve what you need:
public class LapTimer : IDisposable
{
private readonly System.Diagnostics.Stopwatch _stopWatch = new System.Diagnostics.Stopwatch();
private readonly ConcurrentDictionary<string, List<TimeSpan>> _carLapTimes = new ConcurrentDictionary<string, List<TimeSpan>>();
private readonly Action<TimeSpan> _countdownReportingDelegate;
private readonly TimeSpan _countdownReportingInterval;
private System.Threading.Timer _countDownTimer;
private TimeSpan _countdownTo = TimeSpan.FromSeconds(5);
public LapTimer(TimeSpan countdownReportingInterval, Action<TimeSpan> countdownReporter)
{
_countdownReportingInterval = countdownReportingInterval;
_countdownReportingDelegate = countdownReporter;
}
public void StartRace(TimeSpan countdownTo)
{
_carLapTimes.Clear();
_stopWatch.Restart();
_countdownTo = countdownTo;
_countDownTimer = new System.Threading.Timer(this.CountdownTimerCallback, null, _countdownReportingInterval, _countdownReportingInterval);
}
public void RaceComplete()
{
_stopWatch.Stop();
_countDownTimer.Dispose();
_countDownTimer = null;
}
public void CarCompletedLap(string carId)
{
var elapsed = _stopWatch.Elapsed;
_carLapTimes.AddOrUpdate(carId, new List<TimeSpan>(new[] { elapsed }), (k, list) => { list.Add(elapsed); return list; });
}
public IEnumerable<TimeSpan> GetLapTimesForCar(string carId)
{
List<TimeSpan> lapTimes = null;
if (_carLapTimes.TryGetValue(carId, out lapTimes))
{
yield return lapTimes[0];
for (int i = 1; i < lapTimes.Count; i++)
yield return lapTimes[i] - lapTimes[i - 1];
}
yield break;
}
private void CountdownTimerCallback(object state)
{
if (_countdownReportingDelegate != null)
_countdownReportingDelegate(_countdownTo - _stopWatch.Elapsed);
}
public void Dispose()
{
if (_countDownTimer != null)
{
_countDownTimer.Dispose();
_countDownTimer = null;
}
}
}
class Program
{
public static void Main(params string[] args)
{
using (var lapTimer = new LapTimer(TimeSpan.FromMilliseconds(100), remaining => Console.WriteLine(remaining)))
{
lapTimer.StartRace(TimeSpan.FromSeconds(5));
System.Threading.Thread.Sleep(2000);
lapTimer.RaceComplete();
}
Console.ReadLine();
}
}

Count Parallel port input frequency - C#

I have to count the input frequency of the parallel port at Pin no.13, comming from a 555 timer IC, the real frequency should be around 3-4 Hz (ON Pulse). I have tried several codes, several times but every time those are giving different values. I have tried the following code:
[DllImport("inpout32.dll", EntryPoint = "Inp32")]
public static extern int Input(int adress);
private void button1_Click(object sender, EventArgs e)
{
int currentState = Input(889);
int LastState;
while (true)
{
int State = Input(889);
if (State != currentState)
{
if (Input(889) == 120)
{
LastState = 0;
}
else
{
LastState = 1;
}
break;
}
}
GetFreq(LastState);
}
void GetFreq(int LastPulse)
{
int highPulseFreq = 0;
int lowPulseFreq = 0;
if (LastPulse == 1)
{
highPulseFreq++;
}
if (LastPulse == 0)
{
lowPulseFreq++;
}
int startTime = DateTime.Now.Second;
while (true)
{
if (startTime == DateTime.Now.Second)
{
if (Input(889) != 120)// ON
{
if (LastPulse == 0)
{
highPulseFreq++;
LastPulse = 1;
}
}
else
{
if (LastPulse == 1)
{
lowPulseFreq++;
LastPulse = 0;
}
}
}
else
{
MessageBox.Show("ON Pulses: " + highPulseFreq.ToString() + Environment.NewLine + "OFF Pulses: " + lowPulseFreq.ToString());
break;
}
}
}
OUTPUT:
What should I do, to get accurate frequency? Is any thing wrong in my code?
I am using the inpout32.dll to control parallel port.
You're doing all sorts of things a bit wrong. First, you're counting pulses for an entire second, you're counting pulses for up to a second (depends on where in the second GetFreq is called).
Second, you're counting up and down pulses, although I think the frequency should be the number of up (or down) pulses each second, not both of them (that would be double the frequency).
And finally, if you want to measure 3 or 4 Hz, measuring for one second is going to introduce rounding errors. Try measuring for 5 seconds. Use a Stopwatch to measure those 5 seconds.
Try using the following function instead:
double GetFreq(long time, out int highCount, out int lowCount)
{
const int ADDRESS = 0x378 + 1, MASK = 0x10;
highCount = lowCount = 0;
bool LastState = (Input(ADDRESS) & MASK) == MASK;
if (LastState)
{
highCount++;
}
else
{
lowCount++;
}
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds <= time)
{
if ((Input(ADDRESS) & MASK) == MASK) // High
{
if (!LastState)
{
highCount++;
LastState = true;
}
}
else
{
if (!LastState)
{
lowCount++;
LastState = false;
}
}
}
stopwatch.Stop();
return ((double)(highCount + lowCount)) / time * 500
}
And when you need to call the function, just do the following:
int highCount, lowCount;
double frequenct = GetFreq(1000, out highCount, out lowCount);
In my code, I used bitwise operator AND to mask out unnecessary bits, which should be better than directly comparing against 120. Remember when the results are bitwise, never compare directly using == or != operators.
I used System.Diagnostics.Stopwatch which is a lot more precise than using DateTime.Now.Second.
You need to sample your signal at rate that is at least twice the highest frequency in your signal. If your expected highest frequency is about 4Hz, then sampling the signal anywhere from 15 - 20Hz should give good results.
Fortunately, sampling at this rate is something that can be done without too much futzing around with high precision timers on Windows (if you don't require a lot of accuracy). A 20Hz sample rate corresponds to a sample period of 50ms, so you can use a loop where you sleep for about 50ms between recording sample values. You won't get a super precise delta-T between samples (you may see variations of up to 15-30ms in the time between each sample, depending on your system), but it should be good enough for the frequencies you're dealing with.
You can record several seconds worth of samples (and associated timestamps), and then export the data to a spreadsheet. Once in the spreadsheet, you can do some analysis and graphing. Or you can find some time series analysis code to analyze the list of samples, such as using a Fourier transform (FFT) to convert a signal from the time domain to the frequency domain.
Here is an example of creating the samples. You can replace the use of DateTime.Now with a StopWatch in GetInputSamples if you really need more accuracy in the timestamps.
[DllImport("inpout32.dll", EntryPoint = "Inp32")]
public static extern int Input(int adress);
struct Sample
{
public int Value;
public int Milliseconds;
};
private void button1_Click(object sender, EventArgs e)
{
TimeSpan duration = TimeSpan.FromSeconds(5);
TimeSpan samplePeriod = TimeSpan.FromMilliseconds(50);
var samples = GetInputSamples(889, duration, samplePeriod);
SaveSamplesCSV(samples, "test.csv");
}
private static List<Sample> GetInputSamples(int inputPort, TimeSpan duration, TimeSpan samplePeriod)
{
List<Sample> samples = new List<Sample>();
var oldPriority = Thread.CurrentThread.Priority;
try
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
DateTime start = DateTime.Now;
while (DateTime.Now - start < duration)
{
int value = Input(inputPort);
TimeSpan timestamp = DateTime.Now - start;
samples.Add(new Sample() { Value = value, Milliseconds = (int)timestamp.TotalMilliseconds });
Thread.Sleep(samplePeriod);
}
}
finally
{
Thread.CurrentThread.Priority = oldPriority;
}
return samples;
}
private static void SaveSamplesCSV(List<Sample> samples, string fileName)
{
using (StreamWriter writer = File.CreateText(fileName))
{
writer.WriteLine("Sample, Time (ms)");
foreach (var sample in samples)
{
writer.WriteLine("{0}, {1}", sample.Value, sample.Milliseconds);
}
}
}

ThreadQueue problems in "Accelerated C# 2008"

Example for threading queue book "Accelerated C# 2008" (CrudeThreadPool class) not work correctly. If I insert long job in WorkFunction() on 2-processor machine executing for next task don't run before first is over. How to solve this problem? I want to load the processor to 100 percent
public class CrudeThreadPool
{
static readonly int MAX_WORK_THREADS = 4;
static readonly int WAIT_TIMEOUT = 2000;
public delegate void WorkDelegate();
public CrudeThreadPool()
{
stop = 0;
workLock = new Object();
workQueue = new Queue();
threads = new Thread[MAX_WORK_THREADS];
for (int i = 0; i < MAX_WORK_THREADS; ++i)
{
threads[i] = new Thread(new ThreadStart(this.ThreadFunc));
threads[i].Start();
}
}
private void ThreadFunc()
{
lock (workLock)
{
int shouldStop = 0;
do
{
shouldStop = Interlocked.Exchange(ref stop, stop);
if (shouldStop == 0)
{
WorkDelegate workItem = null;
if (Monitor.Wait(workLock, WAIT_TIMEOUT))
{
// Process the item on the front of the queue
lock (workQueue)
{
workItem = (WorkDelegate)workQueue.Dequeue();
}
workItem();
}
}
} while (shouldStop == 0);
}
}
public void SubmitWorkItem(WorkDelegate item)
{
lock (workLock)
{
lock (workQueue)
{
workQueue.Enqueue(item);
}
Monitor.Pulse(workLock);
}
}
public void Shutdown()
{
Interlocked.Exchange(ref stop, 1);
}
private Queue workQueue;
private Object workLock;
private Thread[] threads;
private int stop;
}
public class EntryPoint
{
static void WorkFunction()
{
Console.WriteLine("WorkFunction() called on Thread 0}", Thread.CurrentThread.GetHashCode());
//some long job
double s = 0;
for (int i = 0; i < 100000000; i++)
s += Math.Sin(i);
}
static void Main()
{
CrudeThreadPool pool = new CrudeThreadPool();
for (int i = 0; i < 10; ++i)
{
pool.SubmitWorkItem(
new CrudeThreadPool.WorkDelegate(EntryPoint.WorkFunction));
}
pool.Shutdown();
}
}
I can see 2 problems:
Inside ThreadFunc() you take a lock(workLock) for the duration of the method, meaning your threadpool is no longer async.
in the Main() method, you close down the threadpool w/o waiting for it to finish. Oddly enough that is why it is working now, stopping each ThreadFunc after 1 loop.
It's hard to tell because there's no indentation, but it looks to me like it's executing the work item while still holding workLock - which is basically going to serialize all the work.
If at all possible, I suggest you start using the Parallel Extensions framework in .NET 4, which has obviously had rather more time spent on it. Otherwise, there's the existing thread pool in the framework, and there are other implementations around if you're willing to have a look. I have one in MiscUtil although I haven't looked at the code for quite a while - it's pretty primitive.

Categories

Resources