What is faster and more efficient - begininvoke or synchronisecontext.post? - c#

Did anyone tried to find out - what is faster and what is more efficient (less objects created and thus less GC is involved) - control.BeginInvoke or SynchroniseContext.Post ?
WPF, C#, .NET 4
I'd appreciate responses with practical backing rather than "I think" or "I heard somewhere"..
Cheers
P.S. I am going to post a number of messages to few controls and I want it to be max efficient and fast (few hundred updates / sec). I know .NET can handle this (I did it before) but now I want it to be as fast as possible...

Firstly, there is no Control.BeginInvoke in WPF (that's winforms you're thinking of). Secondly, SynchronizationContext is an abstraction over whatever synchronization mechanism the current platform provides. In the case of WPF, it's an abstraction over the Dispatcher. Theoretically you pay a small price for using the abstraction rather than directly using the Dispatcher. But the abstraction is there for a good reason - sometimes you need to write thread synchronization code that is independent of the platform. If you don't then by all means use the Dispatcher directly.

The BeginInvoke is 42.8% faster than SynchronizationContext.Post on my i7 desktop.
The results are:
Post Send Diff ms Ratio
1280866 925416 35.00 -38.4%
1192232 916251 27.00 -30.1%
1338990 876215 46.00 -52.8%
1394783 863241 53.00 -61.6%
1332485 1046789 28.00 -27.3%
1335241 895784 43.00 -49.1%
1267470 1064894 20.00 -19.0%
1308461 884136 42.00 -48.0%
1321243 850704 47.00 -55.3%
1313230 896469 41.00 -46.5%
The code :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
}
Thread th;
DispatcherSynchronizationContext ctx;
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Thread.CurrentThread.Priority = ThreadPriority.Highest;
ctx = new DispatcherSynchronizationContext(this.Dispatcher);
th = new Thread(Start);
th.Start();
}
int MACRO = 10;
int TESTS = 10;
int LOOPS = 50000;
void Start()
{
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
// flush just in case
for (int i = 0; i < 100; i++)
{
ctx.Post(Callback, 9999999);
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Send, 9999999);
}
Thread.Sleep(1000);
// results
List<Tuple<long, long>> results = new List<Tuple<long, long>>();
// actual test
for (int x = 0; x < MACRO; x++)
{
Stopwatch sw = new Stopwatch();
// sync context post
long tick1, tick2;
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
ctx.Post(Callback, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick1 = sw.ElapsedTicks;
// begin invoke
sw.Reset();
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Normal, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick2 = sw.ElapsedTicks;
// store results
results.Add(new Tuple<long, long>(tick1, tick2));
// display to make it less boring
this.Dispatcher.BeginInvoke(new Action(() => { txt3.Text += string.Format("{0} {1}. ", tick1, tick2); }));
Thread.Sleep(100);
}
StringBuilder sb = new StringBuilder();
foreach (var res in results)
sb.AppendLine(string.Format("{0}\t{1}\t{2:0.00}\t{3:0.0%}",
res.Item1, res.Item2, (res.Item1 - res.Item2) / 10000, res.Item2 != 0 ? 1.0 - res.Item1 / (double)res.Item2 : 0.0));
this.Dispatcher.BeginInvoke(
new Action(() => { txb1.Text = sb.ToString(); }));
}
void Callback(object state)
{
txt1.Text = state.ToString();
}
}

Related

Trying to assign a large workload into a thread pool (Unity)

I have a very specific and demanding workload I am trying to multithreaded. This is very new to me so I am struggling to find an effective solution.
Program Description: UpdateEquations() is cycling through a list of mathematical functions to update the coordinates of rendered lines. By default, func.Count = 3, so this will call CordCalc() 1500 times every frame. I am using NClac to parse a function string and write the result to the Function list, which will later be used before the end of the frame (irrelevant).
Goal: I want to put each cycle of the for(int a) loop inside its own thread. Since for(int a) will only loop 3 times, I just need to start three threads. I cannot continue the for(int i) loop until for(int a) is fully calculated. I am calculating a very large about of small tasks so it would be too expensive to assign each task to the thread.
What I am currently trying to do: I am trying to use a ThreadPool queue, however I'm not sure how to wait for them all to finish before continuing onto the next for(int i) iteration. Furthermore, while the program compiles and executes, the performance is disastrous. Probably %5 of my original performance. I am not sure if creating a "new WaitCallback" is expensive or not. I was looking for a way to predefined threads somehow so that I don't have to reinitialize them 1500 times a frame. (Which is what I suspect the issue is).
Other things I've tried: I tried using new Thread(() => CordCalc(a, i)); however this seemed to have much worse performance. I saw online somewhere that using a ThreadPool would be less expensive.
(This code is shortened for readability and relevance)
public List<Function> func;
private Expression[] exp;
private int lines_i;
private int lines_a;
public void Start()
{
func = new List<Function>();
exp = new Expression[func.Count];
for (int i = 0; i < func.Count; i++) exp[i] = new Expression(func[i].function);
}
//Calculate
public void CordCalc(object state)
{
for (int b = 0; b < func.Count; b++)
exp[lines_a].Parameters[func[b].name] = func[b].mainCords[lines_i - 1];
exp[lines_a].Parameters["t"] = t;
try
{
func[lines_a].mainCords[lines_i] = Convert.ToSingle(exp[lines_a].Evaluate());
}
catch
{
Debug.Log("input Error");
func[lines_a].mainCords[lines_i] = 0;
}
}
private void UpdateEquations()
{
//Initialize equations
for (int a = 0; a < func.Count; a++)
{
func[a].mainCords[0] = t;
}
lines_i = 1;
for (int i = 1; i < 500; i++)
{
lines_a = 0;
for (int a = 0; a < func.Count; a++)
{
//Calculate
ThreadPool.QueueUserWorkItem(new WaitCallback(CordCalc));
//This was something else that I tried, which gave worse results:
//threads[a] = new Thread(() => CordCalc(a, i));
//threads[a].Start();
//t.Join();
//This was my original method call without multithreading
//func[a].mainCords[i] = CordCalc(a, i);
lines_a++;
}
lines_i++;
}
private void FixedUpdate()
{
t += step * (2 + step) * 0.05f;
UpdateEquations();
}
//Function List
public class Function
{
public string name;
public string function;
public float[] mainCords;
//Constructor
public Function(string nameIn, string funcIn)
{
name = nameIn;
function = funcIn;
}
public void SetSize(int len)
{
mainCords = new float[len];
}
}

Threading on Winforms

I am teaching myself how to operate with large numbers in complex loops.
In the main program, it will calling an method to perform some action.
In the example that I am working on it is just displaying the time in seconds.
As I am working the Form goes to Not Responding and crashes.
The screen looks like
When the program is running, every second would be outputted to the screen letting the user see that the program is still running and not responding.
The code is as follows
private void BtnStart_Click(object sender, EventArgs e)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
label1.Text = "Start";
label2.Text = "Started";
dataGridView1.ColumnCount = 1;
dataGridView1.Columns[0].Name = "Number";
for (int index1 = 0; index1 < limit; index1++)
{
for (int index2 = 0; index2 < limit; index2++)
{
for (int index3 = 0; index3 < limit; index3++)
{
if ((stopwatch.ElapsedMilliseconds % 1000) == 0)
{
timeCount++;
AddRowToDG();
}
count++;
}
}
}
label1.Text = "The count is " + count.ToString();
// Stop.
stopwatch.Stop();
Double myTime = stopwatch.ElapsedMilliseconds;
label2.Text = (myTime / 1000).ToString();
}
private void AddRowToDG()
{
dataGridView1.Rows.Add(timeCount.ToString());
}
If I use above 150 for the limit, the program goes to not responding.
In the programming that I will be actually using will be 10 to power of 12.
From the research that I have done, there is tasks and threads that can be used.
Which methodology should I use and where would I get the best resource to help me to make the choices in future?
C# language have System.Threading.Tasks.Task and System.Threading.Thread classes, but for Windows Forms you should use System.ComponentModel.BackgroundWorker. There is DoWork event to do your application logic in the different thread.

Using for loop to add tasks for creating a task scheduler that limits concurrency

I followed the example at MSDN to make my own demo for creating a task scheduler that limits concurrency.
The maxDegreeOfParallelism is set to 2.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskSchedulerThatLimitsConcurrency
{
class Program
{
static void Main(string[] args)
{
// Create a scheduler that uses two threads.
LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(2);
List<Task> tasks = new List<Task>();
// Create a TaskFactory and pass it our custom scheduler.
TaskFactory factory = new TaskFactory(lcts);
CancellationTokenSource cts = new CancellationTokenSource();
// Use our factory to run a set of tasks.
Object lockObj = new Object();
for (int i = 0; i < 4; i++)
{
var myFactory = new TaskFactory(lcts);
Task t = myFactory.StartNew(() =>
{
if (cts.IsCancellationRequested)
return;
lock (lockObj)
{
MakeTest(i, 1);
}
}, cts.Token);
tasks.Add(t);
}
for (int i = 0; i < 4; i++)
{
var myFactory = new TaskFactory(lcts);
Task t1 = myFactory.StartNew(() =>
{
if (cts.IsCancellationRequested)
return;
lock (lockObj)
{
MakeTest(i, 2);
}
}, cts.Token);
tasks.Add(t1);
}
// Wait for the tasks to complete before displaying a completion message.
Task.WaitAll(tasks.ToArray());
Console.WriteLine("\n\nSuccessful completion.");
Console.Read();
}
private static void MakeTest(int i, int p)
{
StringBuilder sb = new StringBuilder();
sb.Append(i.ToString() + "_" + p.ToString());
Console.WriteLine(sb.ToString());
}
}
}
The result is
The task t1 and t2 is almost same. The difference is MakeTest(i, 1) and MakeTest(i, 2). I wonder that can I use a second for loop to add the task?
I used the following code but obviously the result is wrong.
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
{
var myFactory = new TaskFactory(lcts);
Task t1 = myFactory.StartNew(() =>
{
if (cts.IsCancellationRequested)
return;
lock (lockObj)
{
MakeTest(i, j+1);
}
}, cts.Token);
tasks.Add(t1);
}
}
The result:
Questions:
Why my original code did not output the correct results such as "0_1", "1_1", etc.?
If with the second loop in my modified code, how to generate the correct results? Because in my real case the max DegreeOfParallelism is a big number. I can not add one by one to the task list as MSDN example. I thought that I have to use a for loop.
The lambda that you are passing to StartNew creates a closure over the variables i and j. Because it's the variable that's closed-over and not the value of that variable, MakeTest() will be passed the value of i and j at the time that MakeTest() is called, rather than their value at the time you call StartNew. Supposing that your for loops complete before the first thread reaches that point in code, you'll always get the last value that i and j had as they passed through the for loop.
For more information, see Eric Lippert's article: http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
A simple fix would be to declare new variables inside of your for loops. Since these variables would be scoped within the loop, the captured value would remain what value that variable had during that particular iteration:
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
{
var capturedI = i;
var capturedJ = j;
...
MakeTest(capturedI, capturedJ+1);
...

How to block new threads until all threads are created and started

I am building a small application simulating a horse race in order to gain some basic skill in working with threads.
My code contains this loop:
for (int i = 0; i < numberOfHorses; i++)
{
horsesThreads[i] = new Thread(horsesTypes[i].Race);
horsesThreads[i].Start(100);
}
In order to keep the race 'fair', I've been looking for a way to make all newly created threads wait until the rest of the new threads are set, and only then launch all of them to start running their methods (Please note that I understand that technically the threads can't be launched at the 'same time')
So basically, I am looking for something like this:
for (int i = 0; i < numberOfHorses; i++)
{
horsesThreads[i] = new Thread(horsesTypes[i].Race);
}
Monitor.LaunchThreads(horsesThreads);
Threading does not promise fairness or deterministic results, so it's not a good way to simulate a race.
Having said that, there are some sync objects that might do what you ask. I think the Barrier class (Fx 4+) is what you want.
The Barrier class is designed to support this.
Here's an example:
using System;
using System.Threading;
namespace Demo
{
class Program
{
private void run()
{
int numberOfHorses = 12;
// Use a barrier with a participant count that is one more than the
// the number of threads. The extra one is for the main thread,
// which is used to signal the start of the race.
using (Barrier barrier = new Barrier(numberOfHorses + 1))
{
var horsesThreads = new Thread[numberOfHorses];
for (int i = 0; i < numberOfHorses; i++)
{
int horseNumber = i;
horsesThreads[i] = new Thread(() => runRace(horseNumber, barrier));
horsesThreads[i].Start();
}
Console.WriteLine("Press <RETURN> to start the race!");
Console.ReadLine();
// Signals the start of the race. None of the threads that called
// SignalAndWait() will return from the call until *all* the
// participants have signalled the barrier.
barrier.SignalAndWait();
Console.WriteLine("Race started!");
Console.ReadLine();
}
}
private static void runRace(int horseNumber, Barrier barrier)
{
Console.WriteLine("Horse " + horseNumber + " is waiting to start.");
barrier.SignalAndWait();
Console.WriteLine("Horse " + horseNumber + " has started.");
}
private static void Main()
{
new Program().run();
}
}
}
[EDIT] I just noticed that Henk already mentioned Barrier, but I'll leave this answer here because it has some sample code.
I'd be looking at a ManualResetEvent as a gate; inside the Thread, decrement a counter; if it is still non-zero, wait on the gate; otherwise, open the gate. Basically:
using System;
using System.Threading;
class Program
{
static void Main()
{
ManualResetEvent gate = new ManualResetEvent(false);
int numberOfThreads = 10, pending = numberOfThreads;
Thread[] threads = new Thread[numberOfThreads];
ParameterizedThreadStart work = name =>
{
Console.WriteLine("{0} approaches the tape", name);
if (Interlocked.Decrement(ref pending) == 0)
{
Console.WriteLine("And they're off!");
gate.Set();
}
else gate.WaitOne();
Race();
Console.WriteLine("{0} crosses the line", name);
};
for (int i = 0; i < numberOfThreads; i++)
{
threads[i] = new Thread(work);
threads[i].Start(i);
}
for (int i = 0; i < numberOfThreads; i++)
{
threads[i].Join();
}
Console.WriteLine("all done");
}
static readonly Random rand = new Random();
static void Race()
{
int time;
lock (rand)
{
time = rand.Next(500,1000);
}
Thread.Sleep(time);
}
}

For loop in many threads

How can I run each call for loop in another thread, but continuation of ExternalMethod should wait to ending of last working thread from for loop (and synchronize) ?
ExternalMethod()
{
//some calculations
for (int i = 0; i < 10; i++)
{
SomeMethod(i);
}
//continuation ExternalMethod
}
One approach would be to use a ManualResetEvent.
Consider the following code (note that this should not be taken as a working example, stuck on OSX so don't have VS nor a C# compiler to hand to check this over):
static ManualResetEvent mre = new ManualResetEvent(false);
static int DoneCount = 0;
static int DoneRequired = 9;
void ExternalMethod() {
mre.Reset();
for (int i = 0; i < 10; i++) {
new Thread(new ThreadStart(ThreadVoid)).Start();
}
mre.WaitOne();
}
void ThreadVoid() {
Interlocked.Increment(ref DoneCount);
if (DoneCount == DoneRequired) {
mre.Set();
}
}
IMPORTANT - This possibly isn't the best way to do it, just an example of using ManualResetEvent, and it will suit your needs perfectly fine.
If you're on .NET 4.0 you can use a Parallel.For loop - explained here.
System.Threading.Tasks.Parallel.For(0, 10, (i) => SomeMethod(i));
One approach is to use a CountdownEvent.
ExternalMethod()
{
//some calculations
var finished = new CountdownEvent(1);
for (int i = 0; i < 10; i++)
{
int capture = i; // This is needed to capture the loop variable correctly.
finished.AddCount();
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
SomeMethod(capture);
}
finally
{
finished.Signal();
}
}, null);
}
finished.Signal();
finished.Wait();
//continuation ExternalMethod
}
If CountdownEvent is not available then here is an alternate approach.
ExternalMethod()
{
//some calculations
var finished = new ManualResetEvent(false);
int pending = 1;
for (int i = 0; i < 10; i++)
{
int capture = i; // This is needed to capture the loop variable correctly.
Interlocked.Increment(ref pending);
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
SomeMethod(capture);
}
finally
{
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
}
}, null);
}
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
finished.WaitOne();
//continuation ExternalMethod
}
Note that in both examples the for loop itself is treating as a parallel work item (it is on a separate thread from the other work items afterall) to avoid a really subtle race condition that might occur if the first work item signals the event before the next work item is queued.
For .NET 3.5, maybe something like this:
Thread[] threads = new Thread[10];
for (int x = 0; x < 10; x++)
{
threads[x] = new Thread(new ParameterizedThreadStart(ThreadFun));
threads[x].Start(x);
}
foreach (Thread thread in threads) thread.Join();
It may seem counterintuitive to use the Join() method, but since you are effectively doing a WaitAll-type pattern, it doesn't matter what order the joins are executed.

Categories