Checking if instance is null VS calling empty function (C#) - c#

Introduction
So I was making a game, thinking how do I structure and update all my game objects. Do I (case 1) create a simple GameObj as a parent class and put some physics in virtual Update method, some default drawing in virtual Draw, etc, and make every other object (wall, enemy, player...) be the child, OR do I (case 2) use components as described in this article. In short, the writer explains that we could make interfaces for user input, physics update and draw (lets stop at those 3) and describe our GameObj with preprogrammed instances of these interfaces.
Now, in both cases I will get a loop of GameObj class.
In case 1 it would probably look something like this
// in Update function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].Update();
}
And in case 2, something like this
// in UpdatePhysics function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].PhysicComponent.Update();
}
And so on (in case 2) for other interfaces such as InputComponent.Update and DrawComponent.Draw (or CollisionComponent.Check(gameObj[x]), I dunno).
Reasons listed are ment to be inside a level class that takes care of all of our game objects
Reasons to consider if ( x != null )
In both cases we (could) have a situation where we need to call if ( x != null ). In case 1 we maybe don't want to delete and add to the gameObjList all the time, but recycle the instances, so we set them to null without doing something along the lines of gameObjList.Remove(x). In case 2 maybe we want to be able not to set some of the components, so we'd have to ask if (gameObjList[i].someComponent != null) to be able to call gameObjList[i].someComponent.Update().
Reasons to consider calling empty function
Also in both cases, we could just call an empty function (e.g. public void myFunction(){}). Lets consider the self explanatory Wall class. It exists just to be there. Id doesn't update, but it does have a certain relation to other GameObjs. Also, some of it's children in case 1, like a lets say MovingWall or Platform would have some sort of update. As for case 2, we could always declare a default, empty class of someComponent whose Update function would be empty, and so an instance of this class would be set to our GameObj component if none is set in the constructor. Maybe something like this
public GameObj(IPhysicsComponent physicsComponent, ...){
if(physicsComponent == null)
physicsComponent = PhysicsComponent.Default;
this.physicsComponent = physicsComponent;
}
Research
Now, I didn't find what would be the most efficient thing to do in a game engine we are building here. Here are some examples I just tested (note some of them are just for reference):
1. empty loop
2. empty function
3. if(x != null) x.empyFunction(); x is always null
4. x?.emptyFunction(); x is always null
5. if(x != null) x.empyFunction(); x is not null
6. x?.emptyFunction(); x is not null
7. myClass.staticEmptyFunction();
These 7 points are tested 100 000 times, 10 000 times. The code below is the code that I tested with. You can run in locally, change some of the static variables, and the result will appear in "result.txt" in the folder where you ran the program. Here is the code :
public enum TimeType
{
emptyLoop = 1,
loopEmptyFunction = 2,
loopNullCheck = 3,
loopNullCheckShort = 4,
loopNullCheckInstanceNotNull = 5,
loopNullCheckInstanceNotNullShort = 6,
loopEmptyStaticFunction = 7
}
class myTime
{
public double miliseconds { get; set; }
public long ticks { get; set; }
public TimeType type { get; set; }
public myTime() { }
public myTime(Stopwatch stopwatch, TimeType type)
{
miliseconds = stopwatch.Elapsed.TotalMilliseconds;
ticks = stopwatch.ElapsedTicks;
this.type = type;
}
}
class myClass
{
public static void staticEmptyFunction() { }
public void emptyFunction() { }
}
class Program
{
static List<myTime> timesList = new List<myTime>();
static int testTimesCount = 10000;
static int oneTestDuration = 100000;
static void RunTest()
{
Stopwatch stopwatch = new Stopwatch();
Console.Write("TEST ");
for (int j = 0; j < testTimesCount; j++)
{
Console.Write("{0}, ", j + 1);
myClass myInstance = null;
// 1. EMPTY LOOP
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)1));
stopwatch.Reset();
// 3. LOOP WITH NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)3));
stopwatch.Reset();
// 4. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)4));
stopwatch.Reset();
myInstance = new myClass();
// 2. LOOP WITH EMPTY FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)2));
stopwatch.Reset();
// 5. LOOP WITH NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)5));
stopwatch.Reset();
// 6. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)6));
stopwatch.Reset();
// 7. LOOP WITH STATIC FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myClass.staticEmptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)7));
stopwatch.Reset();
}
Console.WriteLine("\nDONE TESTING");
}
static void GetResults()
{
// SUMS
double sum1t, sum2t, sum3t, sum4t, sum5t, sum6t, sum7t,
sum1m, sum2m, sum3m, sum4m, sum5m, sum6m, sum7m;
sum1t = sum2t = sum3t = sum4t = sum5t = sum6t = sum7t =
sum1m = sum2m = sum3m = sum4m = sum5m = sum6m = sum7m = 0;
foreach (myTime time in timesList)
{
switch (time.type)
{
case (TimeType)1: sum1t += time.ticks; sum1m += time.miliseconds; break;
case (TimeType)2: sum2t += time.ticks; sum2m += time.miliseconds; break;
case (TimeType)3: sum3t += time.ticks; sum3m += time.miliseconds; break;
case (TimeType)4: sum4t += time.ticks; sum4m += time.miliseconds; break;
case (TimeType)5: sum5t += time.ticks; sum5m += time.miliseconds; break;
case (TimeType)6: sum6t += time.ticks; sum6m += time.miliseconds; break;
case (TimeType)7: sum7t += time.ticks; sum7m += time.miliseconds; break;
}
}
// AVERAGES
double avg1t, avg2t, avg3t, avg4t, avg5t, avg6t, avg7t,
avg1m, avg2m, avg3m, avg4m, avg5m, avg6m, avg7m;
avg1t = sum1t / (double)testTimesCount;
avg2t = sum2t / (double)testTimesCount;
avg3t = sum3t / (double)testTimesCount;
avg4t = sum4t / (double)testTimesCount;
avg5t = sum5t / (double)testTimesCount;
avg6t = sum6t / (double)testTimesCount;
avg7t = sum7t / (double)testTimesCount;
avg1m = sum1m / (double)testTimesCount;
avg2m = sum2m / (double)testTimesCount;
avg3m = sum3m / (double)testTimesCount;
avg4m = sum4m / (double)testTimesCount;
avg5m = sum5m / (double)testTimesCount;
avg6m = sum6m / (double)testTimesCount;
avg7m = sum7m / (double)testTimesCount;
string fileName = "/result.txt";
using (StreamWriter tr = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + fileName))
{
tr.WriteLine(((TimeType)1).ToString() + "\t" + avg1t + "\t" + avg1m);
tr.WriteLine(((TimeType)2).ToString() + "\t" + avg2t + "\t" + avg2m);
tr.WriteLine(((TimeType)3).ToString() + "\t" + avg3t + "\t" + avg3m);
tr.WriteLine(((TimeType)4).ToString() + "\t" + avg4t + "\t" + avg4m);
tr.WriteLine(((TimeType)5).ToString() + "\t" + avg5t + "\t" + avg5m);
tr.WriteLine(((TimeType)6).ToString() + "\t" + avg6t + "\t" + avg6m);
tr.WriteLine(((TimeType)7).ToString() + "\t" + avg7t + "\t" + avg7m);
}
}
static void Main(string[] args)
{
RunTest();
GetResults();
Console.ReadLine();
}
}
When I put all the data in excel and made a chart, it looked like this (DEBUG):
EDIT - RELEASE version. I guess this answers my question.
The questions are
Q1. What approach to use to be more efficient?
Q2. In what case?
Q3. Is there official documentation on this?
Q4. Did anybody else test this, maybe more intensively?
Q5. Is there a better way to test this (is my code at fault)?
Q6. Is there a better way around the problem of huge lists of instances that need to be quickly and efficiently updated, as in - every frame?
EDIT Q7. Why does the static method take so much longer to execute in the release version?

As #grek40 suggested, I did another test where I called myClass.staticEmptyFunction(); 100 times before starting the test so that it can be cashed. I also did set testTimesCount to 10 000 and oneTestDuration to 1 000 000. Here are the results:
Now, it seems much more stable. Even the little differences you can spot I blame on my google chrome, excel and deluge running in the background. The questions I asked I asked because I thought that there would be a greater difference, but I guess that the optimisation worsk much much better than I expected. I also guess that nobody did this test because they probably knew that there's C behind it, and that people did amasing work on the optimisation.

Related

custom threads in my code?

I need to create a program scraping a website.
And I did use Thread to solve.
Example:
I have 100 pages and I need divide it, instead of get each page I need custom Thread number to get page:
2 threads - 50 pages/thread
4 threads - 25 pages/thread
I tried my code below, however when to the last page of each thread that very slow.
Before I ask I used to find the way to solve but I can't, therefore I need help.
int so_thread = 10;//thread number
int page_du = 0;
List<NameValueCollection> List_item = new List<NameValueCollection>();
Thread[] threads = new Thread[so_thread];
int dem = 0;
await Task.Run(() =>
{
for (int i = 1; i <= so_thread; i++)
{
if ((Int32.Parse(o_sopage.Text) % so_thread) != 0 && i == so_thread)
{
page_du = Int32.Parse(o_sopage.Text) % so_thread;//Int32.Parse(o_sopage.Text) == page number need get
}
threads[i - 1] = new Thread((object data) =>
{
Array New_Data = new object[2];
New_Data = (Array)data;
int _i = (int)New_Data.GetValue(0);
int _pagedu = (int)New_Data.GetValue(1);
int page_per_thread = Int32.Parse(o_sopage.Text) / so_thread;//Int32.Parse(o_sopage.Text) == page number need get
for (int j = ((page_per_thread * _i) - page_per_thread) + 1; j <= ((page_per_thread * _i) + _pagedu); j++)
{
//MessageBox.Show(j.ToString());
var TG = ebay.GetPage(j);
lock (List_item)
{
List_item.AddRange(TG);
dem++;
progressBar1.Invoke((MethodInvoker)delegate
{
progressBar1.Value = dem;
});
}
}
});
object DATA = new object[2] { i, page_du };
threads[i - 1].Start(DATA);
}
});
Use Parallel.ForEach instead of creating the threads on your own.
Parallel.ForEach(yourCollection, () => { /* your code here */});

Duplicate math result in Bakery Algorithm (C# code)

Index out of bounds when create new thread with parameters? - Continue to my previous topic , now i got a new problem with my my Bakery Algorithm code !
Here's my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace BakeryAlgorithm
{
class Program
{
static int threads = 10;
static string x = "";
static int count = 0;
static int[] ticket = new int[threads];
static bool[] entering = new bool[threads];
public static void doLock(int pid)
{
for (int i = 0; i < threads; i++)
{
ticket[i] = 0;
entering[i] = false;
}
entering[pid] = true;
int max = 0;
for (int i = 0; i < threads; i++)
{
if (ticket[i] > ticket[max]) { max = i; }
}
ticket[pid] = 1+max;
entering[pid] = false;
for (int i = 0; i < threads; ++i)
{
if (i != pid)
{
while (entering[i])
{
Thread.Yield();
}
while (ticket[i] != 0 && (ticket[pid] > ticket[i] ||
(ticket[pid] == ticket[i] && pid > i)))
{
Thread.Yield();
}
}
}
if (x == "C" || x == "c")
Console.WriteLine("[System] PID " + pid.ToString() + " get into critical section");
}
public static void unlock(int pid)
{
ticket[pid] = 0;
count++;
Console.WriteLine("[Thread] PID " + pid.ToString() + " complete.");
}
public static void arrayInit()
{
for (int i = 0; i < threads; i++)
{
ticket[i] = 0;
entering[i] = false;
}
}
public static void simThread(int i)
{
doLock(i);
if (x == "C" || x=="c")
Console.WriteLine("[Thread] PID " + i.ToString() + " begin to process...");
//Do some thing ????
Random rnd = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
int a = rnd.Next(1,99);
int b = rnd.Next(1,99);
int c = rnd.Next(1,4);
int d = 0;
string o="";
if (c == 1)
{
d = a + b;
o="+";
}
else if (c == 2)
{
d = a * b;
o="*";
}
else if (c == 3)
{
d = a / b;
o="/";
}
else
{
d = a - b;
o="-";
}
if (x == "C" || x == "c")
Console.WriteLine("Math Result : " + a.ToString() + o + b.ToString() + "=" + d.ToString());
unlock(i);
}
[STAThread]
static void Main(string[] args)
{
arrayInit();
string choice="C";
while (choice == "C" || x == "c")
{
Console.WriteLine("Process log (C=Yes,K=No) : ");
x = Console.ReadLine();
if (x == "")
x = "C";
Console.Clear();
Console.WriteLine("----------------------------------");
Console.WriteLine("Bakery Algorithm C#");
Console.WriteLine("Number of threads : " + threads.ToString());
Console.WriteLine("Process Log...");
Console.WriteLine("----------------------------------");
Thread[] threadArray = new Thread[threads];
for (int i = 0; i < 10; i++)
{
int copy = i;
threadArray[i] = new Thread(() => simThread(copy));
if (x == "C" || x == "c")
Console.WriteLine("[System] PID " + i.ToString() + " created");
threadArray[i].Start();
}
Console.ReadLine();
Console.WriteLine("----------------------------------");
Console.WriteLine("Complete processed " + count.ToString() + " threads !");
count = 0;
Console.WriteLine("----------------------------------");
Console.WriteLine("You want to restart (Yes=C or No=K)");
choice = Console.ReadLine();
if (choice == "")
choice = "C";
}
}
}
}
The result are here :
2*2=4
2*2=4 << duplicated
3*2=6
4*2=8
4*6=24
4*2=8 << duplicated
.... and continue with duplicate values ( random position ) !
Hope somebody here can help !
There's many things wrong with your code, but the most important part is that you didn't read the requirements that make Lamport's bakery work:
Lamport's bakery algorithm assumes a sequential consistency memory model.
You will be hard-pressed to find a modern computer that has sequential consistency.
So even if your implementation was correct with respect to those constraints, it would still be wrong on pretty much any computer that runs .NET. To make this work on a modern CPU and in .NET, you'll need to insert memory barriers to prevent instruction reordering and introduce cache refreshing to make sure each CPU core sees the same values... and by then you're probably better off using different synchronization primitives altogether.
Now, fixing these kinds of algorithms tends to be rather hard - multi-threading is hard on its own, doing lock-less multi-threading just pushes this to absurd territory. So let me just address some points:
1) You can't just use new Random() and expect statistically random numbers from that. Random has an internal state that's by default initialized to the current OS tick - that means that creating 10 Randoms in a row and then doing Next on each of those is pretty likely to produce exactly the same "random" numbers.
One way of handling that gracefully would be to have a thread-local field:
ThreadLocal<Random> rnd
= new ThreadLocal<Random>(() => new Random(Guid.NewGuid().GetHashCode()));
Each of your threads can then safely do rnd.Value.Next(...) and get reliable numbers without locking.
However, since the whole point of this excercise is to allow shared access to mutable state, a solution more in line with the task would be to use a single shared Random field instead (created only once, before starting the threads). Since the Bakery algorithm is supposed to make sure you can safely use shared stuff in the critical section, this should be safe, if implemented correctly :)
2) To actually make the Bakery part work, you need to enforce the only proper instruction ordering.
This is hard. Seriously.
I'm not actually sure how to do this safely.
The best way to start is to insert an explicit memory barrier before and after each read and write of shared state. Then you can go one by one and remove those that aren't necessary. Of course, you should only need this in the doLock and unlock methods - the rest of simThread should be single-threaded.
For a short sample:
Thread.MemoryBarrier();
entering[pid] = true;
Thread.MemoryBarrier();
int max = 0;
for (int i = 0; i < threads; i++)
{
if (ticket[i] > ticket[max]) { max = i; }
}
Thread.MemoryBarrier();
ticket[pid] = 1+max;
Thread.MemoryBarrier();
entering[pid] = false;
Thread.MemoryBarrier();
So, which one of those is it safe to remove? I have no idea. I'd have to use a lot of mental power to make sure this is safe. Heck, I'm not sure if it's safe as is - do I need to rewrite the for cycle too? Are ticket[i] and ticket[max] going to be fresh enough for the algorithm to work? I know some are definitely needed, but I'm not sure which can safely be left out.
I'm pretty sure this will be slower than using a simple lock, though. For any production code, steer clear away from code like this - "smart" code usually gets you in trouble, even if everyone in your team understands it well. It's kind of hard finding those kinds of experts, and most of those wouldn't touch lock-less code like that with a meter-long stick :)
You must create a different random number for each thread (more details)
so try this code in your main method:
for (int i = 0; i < 10; i++)
{
int temp = i;
threadArray[i] = new Thread(() => simThread(temp));
Console.WriteLine("[He Thong] PID " + i.ToString() + " duoc khoi tao");
threadArray[i].Start();
Thread.Sleep(20);
}
and the following code in you threads:
Random rand = new Random((int) DateTime.Now.Ticks & 0x0000FFFF);
now you can ensure you produce different random number for each thread.
Try:
Random rnd = new Random(Environment.TickCount / (i + 1));
This will give different seeds to each RNG.

Can't add values to List - C# [duplicate]

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 8 years ago.
Many times I had to create lists of structures to store my data in C#. But this time, I have an error, "Index Out of Range". I don't quite understand why, since I already did similar projects, but I would be very appreciated if someone could help me.
class mng
{
int day = 0;
List<Despesas> dias = new List<Despesas>();
public struct Despesas
{
public double transportes;
public double alimentacao;
public double vestuario;
public double agua;
public double luz;
public double educacao;
}
public mng ()
{
}
(This is where I get the error)
public void showMessage()
{
for (int i = 0; i < 31; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}
and on Form1:
double transportes = Convert.ToDouble(txtTransportes.Text);
double agua = Convert.ToDouble(txtAgua.Text);
mng mngV = new mng(transportes, agua, educacao);
if (day < 31)
{
button1.Enabled = false;
//this is the button that enables the ShowMessage() Method.
}
else
{
button1.Enabled = true;
}
I never execute the method showMessage() before the List has 31 values, so why is it out of Index? I tried to search on the site first but couldn't find any questions with a similar problem although there are a lot with the same error.
I changed the overload constructor to:
public mng(double transportes, double agua)
{
Despesas dia = new Despesas();
dia.transportes = transportes;
dia.agua = agua;
dias.Add(dia);
MessageBox.Show("Added: " + dias.Count);
day++;
}
and guess what, the dias.Count is always 1. I don't understand why...
Try changing your method to:
public void showMessage()
{
for (int i = 0; i < dias.Count; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}
What about trying this:
public void showMessage()
{
for (int i = 0; i < dias.Count; i++)
{
MessageBox.Show("Água: " + dias[i].agua + "\nTransportes: " + dias[i].transportes);
}
}
or even better:
public void showMessage()
{
foreach(var d in dias)
{
MessageBox.Show(... + d.agua + .... + d.transportes);
}
}
Just change your code this way:
for (int i = 0; i < dias.Count; i++)
And you can check it under the debugger to verify how many items are there in the array when the loop is running.
make sure that dias has 31 values.you can use foreach instead of for as it will give the the same result with much better performance
foreach(var item in dias )
{
MessageBox.Show("Água: " + item.agua + "\nTransportes: " + item.transportes);
}
if you are using for- than problem is because your list might not filled properly have less items

Am I doing multi threading the right way in c#? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I have a program that runs multiple threads to convert pdf files to images in a folder and its subdirectories. It iterates through that folder, putting all pdf file names in a list, and then use that list to divide up the work between 4 threads that i created. Now it all works perfectly. Multiple threads are running and converting pdf files at the same time to different locations i specify.
I would just like to know if im doing it in the right way. Almost every website i visit do multi threading in a different way, and i don't know which one would be the most effective and ultimately the right one.
No good doing some thing that works, if its done wrong i guess... Just going to get me in the future.
I would love if you could just look at the code here and see if there is anything Drastically wrong that i need to change regarding multiple threads running
static object LockInteger = new object();
static object LockIfCheck = new object();
static object LockInteger = new object();
static object LockIfCheck = new object();
private void button1_Click(object sender, EventArgs e)
{
IterateThrough(txtboxdirectory.Text);
}
public void IterateThrough(string sourceDir)
{
MulThread = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = 0;
int upperbound = (fileList.Count / 4);
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList,sourceDir, dir1);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread.Start();
MulThread1 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = fileList.Count / 4;
int upperbound = (fileList.Count / 4) * 2;
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir2);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread1.Start();
MulThread2 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = (fileList.Count / 4) * 2;
int upperbound = (fileList.Count / 4) * 3;
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir3);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread2.Start();
MulThread3 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = (fileList.Count / 4) * 3;
int upperbound;
if (fileList.Count % 4 != 0)
{
upperbound = ((fileList.Count / 4) * 4) + (fileList.Count % 4) + 1;
}
else
{
upperbound = ((fileList.Count / 4) * 4) + (fileList.Count % 4);
}
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir4);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread3.Start();
}
Then i lock some of the methods in "forFunction".
private int forFunction(String exceptionFileList, FileInfo z, String compltetedFileList, String sourceDir, String imagedirectory)
{
//heres where it locked up because of this global variable
lock (LockInteger)
{
atPDFNumber++;
}
int blankImage = 1;
int pagesMissing = 0;
//delete the images currently in the folder
deleteCreatedImages(imagedirectory);
//Get the amount of pages in the pdf
int numberPDFPage = numberOfPagesPDF(z.FullName);
//Convert the pdf to images on the users pc
convertToImage(z.FullName, imagedirectory);
//Check the images for blank pages
blankImage = testPixels(imagedirectory, z.FullName);
//Check if the conversion couldnt convert a page because of an error
pagesMissing = numberPDFPage - numberOfFiles;
//int pagesMissing = 0;
//Cancel button is pressed
if (toContinue == 0)
{
return 0;
}
lock (LockIfCheck)
{
//If there is a blank page, or if there is a missing page
if (blankImage == 0 || pagesMissing > 0)
{
myholder = 1;
exceptionFileList += "File Name: " + z.Name + "\r\n"
+ "File Path: " + z.FullName + "\r\n \r\n";
String currentValue = exceptionFileList;
txtboxProblemFiles.BeginInvoke(((Action)(() => txtboxProblemFiles.Text += currentValue.ToString())));
String currentValue3 = z.FullName;
txtboxProblemFiles.BeginInvoke(((Action)(() => listboxProblemFiles.Items.Add(currentValue3))));
}
else
{
compltetedFileList += "Scanning Completed of file: " + "\r\n"
+ "File Name: " + z.Name + "\r\n"
+ "File Path: " + sourceDir + "\r\n \r\n";
}
String currentValue1 = "File Name: " + z.Name + "\r\n";
txtboxCheckedFiles.BeginInvoke(((Action)(() => txtboxCheckedFiles.Text += currentValue1)));
}
myWorkerClass();
return 1;
}
I'll accept any up building criticism from this code.
The suggested way for multitrheading is by using ThreadPool.
The benefit of ThreadPool is that it manages thread creation, job assignment ,... and gives you better performance alongside less resource usage.
A sample of ThreadPool from MSDN:
using System;
using System.Threading;
public class Example {
public static void Main() {
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo) {
// No state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Console.WriteLine("Hello from the thread pool.");
}
}
I guess the answer is that depends. Are you starting threads, yes. Does it look like you are protecting shared data yes. It does look like you have copy-pasted code everywhere. That could be abstracted into a function and the upper and lower bounds made into arguments. I think you might be able to reduce this and use the Parallel.For or Parallel.ForEach. Lastly, I can't quite remember the multithreading issue that relates to GUI. I see that you are using some GUI here. But you need to make sure that the change to the labels are made by the GUI thread and not some other thread.

find and findindex painful slow for List<Object> why?

Im am working in a project that uses intensively List and i try to find the object via the name (that is a member of the object).
My code worked without searching it using a single for-next loop (function find1) but i found that it is possible to the same using the build-in found find, and the code works. However, it feel a bit slow. So, i did a project for test the speed:
I have the next code
public List<MyObject> varbig = new List<MyObject>();
public Dictionary<string,string> myDictionary=new Dictionary<string, string>();
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
myDictionary.Clear();
varbig.Clear();
for (int i = 0; i < 5000; i++) {
varbig.Add(new MyObject("name" + i.ToString(),"value"+i.ToString()));
myDictionary.Add("name" + i.ToString(), i.ToString());
}
// first test
var start1 = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss=find1("name499");
}
var end1 = Environment.TickCount;
Console.WriteLine("time 1 :" + (end1 - start1));
// second test
var start2 = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss=find2("name499");
}
var end2 = Environment.TickCount;
Console.WriteLine("time 2 :" + (end2 - start2));
// third test
var start3 = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss = find3("name499");
}
var end3 = Environment.TickCount;
Console.WriteLine("time 3 :" + (end3 - start3));
// first test b
var start1b = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss=find1("name4999");
}
var end1b = Environment.TickCount;
Console.WriteLine("timeb 1 :" + (end1b - start1b));
// second test
var start2b = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss=find2("name4999");
}
var end2b = Environment.TickCount;
Console.WriteLine("timeb 2 :" + (end2b - start2b));
// third test
var start3b = Environment.TickCount;
for (int i = 0; i < 3000; i++) {
var ss = find3("name4999");
}
var end3b = Environment.TickCount;
Console.WriteLine("timeb 3 :" + (end3b - start3b));
}
public int find1(string name) {
for (int i = 0; i < varbig.Count; i++) {
if(varbig[i].Name == name) {
return i;
}
}
return -1;
}
public int find2(string name) {
int idx = varbig.FindIndex(tmpvar => Name == name);
return idx;
}
public int find3(string name) {
var ss=myDictionary[name];
return int.Parse(ss);
}
}
And i use the next object
public class MyObject {
private string _name = "";
private string _value = "";
public MyObject() {}
public MyObject(string name, string value) {
_name = name;
_value = value;
}
public string Name {
get { return _name; }
set { _name = value; }
}
public string Value {
get { return _value; }
set { _value = value; }
}
}
Mostly it do the next thing:
I create an array with 5000 elements.
time 1 = search the 499th object (index) using a simple for-next.
time 2 = search the 499th using the build in function find of List
time 3 = it do the search of the 499th element using dictionary.
Timeb 1, timeb 2 and timeb 3 do the same but try to search the 4999th element instead of the 499th element.
I ran a couple of times :
time 1 :141
time 2 :1248
time 3 :0
timeb 1 :811
timeb 2 :1170
timeb 3 :0
time 1 :109
time 2 :1170
time 3 :0
timeb 1 :796
timeb 2 :1170
timeb 3 :0
(the small then the fast)
And, for my surprise, the build in function findindex is absurdly slow (in some cases, close to 10x slower. Also, the dictionary approach is almost instantly.
My question is, why?. is it because the predicate?.
The problem is in this line:
int idx = varbig.FindIndex(tmpvar => Name == name);
Name == name is wrong, you should write tmpvar.Name == name instead.
In your code you're comparing name argument with the Name property of your form; they are obviously different, and so the method always examines the whole list instead of stopping when the searched value is found. In fact, as you can see looking the numbers, the time spent by find2() is basically always equal.
About the dictionary, it's obviously faster than the other methods because dictionaries are memory structure specifically built to provide fast keyed access.
In fact they arrive close to O(1) time complexity, while looping a list you have a time complexity equal to O(n).
Find1 is using a simple for( i = 0 to count) method
Find2 uses the built in Find method (which is exactly find1 above), except that you have passed a predicate along with it, which I believe is slowing it down.
Find3 using a dictionary, I would assume is the fastest without any timers, becuase a dictionary uses hashtables under the covers which has an 0(1) look up (contant time)
There is the error in your code - the find2 method uses the Form.Name for the comparison instead of your collection objects names. It should looks like this:
public int find2(string name) {
return varbig.FindIndex((obj) => obj.Name == name);
}
The results without using the Form.Name are more consistent:
time 1 :54
time 2 :50
time 3 :0
timeb 1 :438
timeb 2 :506
timeb 3 :0
You don't need to put for loop to search in find2...
Just call find2 directly, then result will be 0.

Categories

Resources