Impact of locks on multithreading performance [duplicate] - c#

This question already has answers here:
How expensive is the lock statement?
(7 answers)
Closed 5 years ago.
I have a simple class designed to play around with threading. It has a member variable, num, which is initialized to 0, and a method called modify which increments and then decrements num a high number of times. When the program runs, it creates two threads which both run modify, and then starts a timer and starts the threads. It uses a while loop to wait for both threads to finish executing, and then stops the timer and prints the time elapsed to the console. The class:
public class Threading
{
public static void Main()
{
Threading t = new Threading();
t.demo();
}
private int num = 0;
public void doThreading()
{
Thread t1 = new Thread(modify);
Thread t2 = new Thread(modify);
t1.Start();
t2.Start();
Stopwatch timer = new Stopwatch();
timer.Start();
while (thread1.IsAlive || thread2.IsAlive)
{
}
timer.Stop();
Console.WriteLine("Took: " + timer.ElapsedMilliseconds + " milliseconds");
Console.Read();
}
public void modify()
{
for (int i = 0; i < 1000000000; i++)
{
count++;
count--;
}
}
}
After running the program, num will not be 0 because of race conditions. When I add locks to the modify method so that num is 0 after running the program:
public void modify()
{
for (int i = 0; i < 1000000000; i++)
{
lock (this) { count++; }
lock (this) { count--; }
}
}
Then the program takes 8 times as long to execute. I cannot figure out why it would be taking so much longer, I would expect, at most, for it to take 4 times as long to execute. Any idea why it is taking so much longer?

lock can appear to be quite expensive in such a case (all you want is to lock incrementing an int, i.e. make count++ atomic); use Interlocked instead:
public void modify()
{
for (int i = 0; i < 1000000000; i++)
{
Interlocked.Increment(ref count);
Interlocked.Decrement(ref count);
}
}

Related

Thread start passed integer changes itself beyond what it should be [duplicate]

This question already has an answer here:
Thread alters passed Int, if start() is called separately
(1 answer)
Closed 7 years ago.
I have no idea what is going on in this. I'm trying to test thread safety of a class by spawning 100 threads to access it constantly, but it seems my anonymous method parameters are changing themselves to values they should never be and I'm confused as to why. As I have no idea what's going on, I'll just post all the functions involved in testing. Somehow I'm ending up with "Thread 98" getting the parameter "num = 100"... That shouldn't be possible and I have no idea what kind of hokey pokey is going on that is changing the integer. (in method "ThreadWriting(int num)" you'll see the point where I check for "num" to equal 100, where I put a break point to catch the offending thread in the act, and it breaks every time. Otherwise it throws an "IndexOutofRangeException" on the array "counts". I'm just trying to see if my threads are generally getting equal access to the class they're all trying to use at once.
public delegate void TempDel();
public TempDel InvokeTest;
public void TRTest3(Form1 sender)
{
InvokeTest = new TempDel(UpdateInvoke);
Thread t = new Thread(() => ConsoleUpdateTest(sender));
t.IsBackground = true;
t.Start();
POConsole.Instance.MaxLines = 20;
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
}
public ulong[] counts = new ulong[100];
public void ThreadWriting(int num)
{
if(num == 100)
{
bool stop = true;
}
while (true)
{
POConsole.Instance.WriteLine("Hello from Thread " + num);
counts[num]++;
}
}
public void ConsoleUpdateTest(Form1 sender)
{
while(true)
{
sender.Invoke(InvokeTest);
Thread.Sleep(5);
}
}
public void UpdateInvoke()
{
QuickTestBox.Text = POConsole.Instance.FullFeed;
}
All my threads are named, as you can see, and none of them receives the name "Thread 100" so I have no idea how one of the other threads could get passed a parameter of 100 or the parameter could be corrupted in some way.
Apparently my thread-safety checking isn't thread safe in some way?
This is a simple closure issue, you should not be using the for loop counter as a threading parameter issue, issue happens out here, for loop and thread execution do not run at same speed, so value of i can change for multiple threads:
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
Use following modification, create a local variable from loop counter
for(int i = 0; i < 100; i++)
{
int j = i;
Thread t2 = new Thread(() => ThreadWriting(j));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", j);
t2.Start();
}

Multithreaded code to do work using configured number of thread

I want to create a multithreaded application code. I want to execute configured no of threads and each thread do the work. I want to know is this the write approach or do we have better approach. All the threads needs to be executed asynchronously.
public static bool keepThreadsAlive = false;
static void Main(string[] args)
{
Program pgm = new Program();
int noOfThreads = 4;
keepThreadsAlive = true;
for (int i = 1; i <= noOfThreads; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object)i);
}
System.Console.ReadLine();
StopAllThreads();
System.Console.ReadLine();
}
private static void DoWork(object threadNumber)
{
int threadNum = (int)threadNumber;
int counter = 1;
while (keepThreadsAlive)
{
counter = ProcessACK(threadNum, counter);
}
}
private static int ProcessACK(int threadNum, int counter)
{
System.Console.WriteLine("Thread {0} count {1}", threadNum, counter++);
Random ran = new Random();
int randomNumber = ran.Next(5000, 100000);
for (int i = 0; i < randomNumber; i++) ;
Thread.Sleep(2000);
return counter;
}
As others have pointed out, the methods you are using are dated and not as elegant as the more modern C# approach to accomplishing the same tasks.
Have a look at System.Threading.Tasks for an overview of what is available to you these days. There is even a way to set the maximum threads used in a parallel operation. Here is a simple (pseudocode) example:
Parallel.ForEach(someListOfItems, new ParallelOptions { MaxDegreeOfParallelism = 8 }, item =>
{
//do stuff for each item in "someListOfItems" using a maximum of 8 threads.
});
Hope this helps.

Run and stop a method for a minute

timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Start();
MyMethodName();
timer1.Stop();
MyMethodName()
-has a for loop for 90,000 entries (and some validations inside that for loop).
for (int i = 0; i <= 90000; i++)
{
//validations go here
}
When the time in timer1 is done for a minute, i want to stop executing other entries in the for loop.
For example, if 45,000 entries are done in a minute, i want to stop executing the method ie. stop the method after a minute.
However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?
Two things. Firstly Your timer code is not actually connected to the running of MyMethodName. A timer is designed to run processes when the time has elapsed (and possibly at regular intervals depending on how it is set up.
Secondly and more to the point of your question to abort a loop you have to put code inside the loop. The key would be to have a stopwatch or similar start before your loop and then at the beginning of your loop check how much time has elapsed. If it is a minute or more then break;.
The key thing to note is that you will not stop exactly on a minute but you will finish the iteration of the loop that is running when the minute expires and then stop. This is usually what you want since stopping processing midway through something may cause nasty side effects.
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i =0; i<=90000; i++)
{
if (stopwatch.Elapsed>TimeSpan.FromSeconds(5))
break;
Console.WriteLine(i);
Thread.Sleep(1000);
}
Note that Thread.Sleep is there just because otherwise I get through all 90000 iterations too quickly. ;-)
So you would likely need a much different implementation. Consider this:
public class MyForm
{
private BackgroundWorker _worker;
public MyForm()
{
_worker = new BackgroundWorker();
_worker.DoWork += (s, args) =>
{
var timer = Stopwatch().StartNew();
do
{
// do something
} while (timer.ElapsedMilliseconds < 60000)
};
}
}
and then when you want to run it:
_worker.RunWorkerAsync();
However, you could make it even more robust. You could pass the time in like this:
_worker.RunWorkerAsync(60000);
and then in the DoWork handler, do this:
while (timer.ElapsedMilliseconds < (int)args.Argument)
Further, with the BackgroundWorker, you could support cancellation. Just set the WorkerSupportsCancellation flag to true and then in the condition do this:
while (timer.ElapsedMilliseconds < (int)args.Argument && !_worker.CancellationPending)
so, if necessary, you could do this:
_worker.CancelAsync();
Hmm, use a stopwatch instead
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for(int i= 0; i <= 90000; i++)
{
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
if(ts.Seconds >= 60)
break;
}
However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?
The timer will not raise events until you free up the UI thread, which won't occur until after the method completes fully.
If you want to prevent the method from running past a specific duration, you could handle it in your method directly:
MyMethodName(TimeSpan.FromMinutes(1));
Then, in your method:
void MyMethodName(TimeSpan maxRuntime)
{
DateTime expiration = DateTime.Now + maxRuntime;
for (int i = 0; i <= 90000; i++)
{
//validations go here
if (i % 100 == 0) // check every 100?
{
if (DateTime.Now > expiration)
break;
}
}
}
That being said, a better approach would be to push this into a background thread, and cancel as needed.
you can set a flag on in validations to see if it is done or not by hooking up an event handler to the Tick event in the Timer object
//in an area accessible to
//both elements
object readonly _lock = new object();
bool elapsed = false;
where your original code was
elapsed = false;
timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Tick=((sender, everntArgs)=>
{
lock(_lock)
elapsed = true;
});
timer1.Start();
MyMethodName();
timer1.Stop();
Inside of MyMethodName
//inside the loop
for (int i = 0; i <= 90000; i++)
{
//validations go here
lock(_lock)
if(elapsed)
break;
}
If you use a CancellationTokenSource with the CancellationTokenSource(TimeSpan) constructor, it makes it easy to write a method that will cancel an action after a specified time.
You can write a method like so:
public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
{
using (var cancellationTokenSource = new CancellationTokenSource(timeout))
action(cancellationTokenSource.Token);
}
And then you can write any action that takes a CancellationToken as a parameter, like this:
private void action(CancellationToken cancel)
{
int i;
for (i = 0; i < 1000000; ++i)
{
if (cancel.IsCancellationRequested)
break;
Thread.Sleep(10); // Simulate work.
}
Console.WriteLine("action() reached " + i);
}
Which you can use like this:
Console.WriteLine("Started at " + DateTime.Now);
RunTimedAction(action, TimeSpan.FromSeconds(10));
Console.WriteLine("Stopped at " + DateTime.Now);
Let's put this together into a complete demo program:
using System;
using System.Threading;
namespace Demo
{
class Program
{
void run()
{
Console.WriteLine("Started at " + DateTime.Now);
RunTimedAction(action, TimeSpan.FromSeconds(10));
Console.WriteLine("Stopped at " + DateTime.Now);
}
private void action(CancellationToken cancel)
{
int i;
for (i = 0; i < 1000000; ++i)
{
if (cancel.IsCancellationRequested)
break;
Thread.Sleep(10); // Simulate work.
}
Console.WriteLine("action() reached " + i);
}
public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
{
using (var cancellationTokenSource = new CancellationTokenSource(timeout))
action(cancellationTokenSource.Token);
}
static void Main()
{
new Program().run();
}
}
}

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.

Exact time measurement for performance testing [duplicate]

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

Categories

Resources