Multiple Task.Run not waiting/running properly - c#

I'm trying to optimize a heavy process with some tasks, but it seems that after the first iteration it skips the ProcessQueue method run.
private void ImportSheet(Excel.Worksheet Data)
{
this._ImportedSlurry = new ConcurrentQueue<AnalizedDataDTO>();
this._LastRowReached = false;
this._CurrentRow = this._FirstRow;
while(!this._LastRowReached)
{
AnalizedDataDTO ImportedRow = this.ValidateRow(Data, _CurrentRow);
Task task1 = Task.Run(() => ProcessQueue(Enumerable.Range(this._CurrentRow, 50).ToArray(),Data));
Task task2 = Task.Run(() => ProcessQueue(Enumerable.Range(this._CurrentRow+50, 50).ToArray(),Data));
Task.WaitAll(task1, task2);
this._CurrentRow += 100;
}
}
private void ProcessQueue(int[] range, Excel.Worksheet Data)
{
for (int i = range.First(); i < range.Length; i++)
{
AnalizedDataDTO ImportedRow = this.ValidateRow(Data, i);
if (ImportedRow == null)
{
this._LastRowReached = true;
break;
}
else
{
this._ImportedSlurry.Enqueue(ImportedRow);
}
}
}

The problem is your for-loop, to be specific its if-condition.
You should either iterate over range, i.e.
foreach (var i in range)
or iterate over an index, i.e.
foreach (var idx = 0; idx < range.Length; idx++)
{
var i = range[idx];
For example assume that this._CurrentRow == 100, then your version of the for loop would look like:
for (int i = 100 /* range.First() */; i < 50 /* range.Length */; i++)

Related

Method never execute because of yield break statement, how to recover from it?

I have to read multiple xml files from specific folder and store in list, but whenever I used yield break; keyword, the method wasn't called. I am totally stuck here.
Below is my code:
private IEnumerable<SyncEntity> GetUpdatedItemsOfTypePagination(string folderPath)
{
int currentPage = 1;
string finishFilePath = Path.Combine(folderPath, "GetUpdateItemsOfType_Finish.xml");
while (true)
{
string xmlFileFullPath = Path.Combine(folderPath, $"GetUpdateItemsOfType{currentPage}.xml");
bool pageReadCompleted = false;
for (int i = 0; i < 1000; i++) //wait max time of 1,000*0.1 = 100 seconds
{
if (!File.Exists(xmlFileFullPath))
{
if (File.Exists(finishFilePath))
{
yield break;
}
Thread.Sleep(TimeSpan.FromSeconds(0.1));
continue;
}
List<SyncEntity> pageItems = GetUpdatedItemsPage(xmlFileFullPath);
pageReadCompleted = true;
foreach (var syncEntity in pageItems)
{
yield return syncEntity;
}
break;
}
if (!pageReadCompleted)
{
throw new ApplicationException("Timeout reached for GetUpdatedItems method...");
}
currentPage++;
}
}

End a task that has a ui updated inside the task C#

I have the following code:
void Selection()
{
bool solutionFound = false;
int generation = 0;
int distance = int.MaxValue;
while(!solutionFound)
{
generation++;
for (int i = 0; i < population.Length; i++)
{
population[i].CalcFitness(target);
}
matingPool = new List<DNA>();
for (int i = 0; i < population.Length; i++)
{
int n = (int)(population[i].fitness * 100);
for (int j = 0; j < n; j++)
{
matingPool.Add(population[i]);
}
}
for (int i = 0; i < population.Length; i++)
{
int a = StaticRandom.Instance.Next(matingPool.Count);
int b = StaticRandom.Instance.Next(matingPool.Count);
DNA partnerA = matingPool[a];
DNA partnerB = matingPool[b];
if(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
while(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
a = StaticRandom.Instance.Next(matingPool.Count);
b = StaticRandom.Instance.Next(matingPool.Count);
partnerA = matingPool[a];
partnerB = matingPool[b];
}
}
DNA child = partnerA.Crossover(partnerB);
child.Mutate(mutationRate);
population[i] = child;
ThreadHelperClass.SetText(this, display_lbl, i + ": " + child.GetPhrase());
ThreadHelperClass.SetText(this, gen_lbl, "Generations: " + generation);
int compute = LevenshteinDistance.Compute(target, child.GetPhrase());
if(compute < distance)
{
distance = compute;
ThreadHelperClass.SetText(this, bestPhrase_lbl, "Best Phrase: " + child.GetPhrase());
}
if(child.GetPhrase().Equals(target))
{
solutionFound = true;
break;
}
}
}
}
and the following code
public static class ThreadHelperClass
{
delegate void SetTextCallback(Form f, Control ctrl, string t);
public static void SetText(Form form, Control control, string text)
{
//Invoke requires compares the thread ID of the calling thread
//to the thread ID of the creating thread
//If they are different InvokeRequired sets to true
if (control.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
form.Invoke(d, new Object[] { form, control, text });
}
else
control.Text = text;
}
}
I send Selection to another thread using:
Task.Factory.StartNew(() => Selection(), cToken.Token);
I've already tried to set the ThreadHelper class to use BeginInvoke instead of Invoke and it locks up my UI on the first iteration of the Selection method.
I've also tried to end the task using cToken.Cancel(). This still locks up my UI when the user clicks the stop_btn.
Is there a way I can stop this from happening?

background worker not responding in our code

i have following code and telerik grid my records are 1266880 background worker are hangout for one minutes i try many ways but cannot success anyone know my application does not hang
PopulateUI(List<DataRow> list)
{
this.Invoke(new MethodInvoker(delegate
{
int Count = list.Count;
grdFares.RowCount = Count;
// grdFares.BeginUpdate();
for (int i = 0; i < grdFares.RowCount; i++)
{
grdFares.Rows[i].Cells[COLS.Id].Value = list[i].ItemArray[0].ToStr();
grdFares.Rows[i].Cells[COLS.FROMLOCATION].Value = list[i].ItemArray[7].ToString();
grdFares.Rows[i].Cells[COLS.TOLOCATION].Value = list[i].ItemArray[8].ToString();
grdFares.Rows[i].Cells[COLS.FARE].Value = list[i].ItemArray[4].ToString();
grdFares.Rows[i].Cells[COLS.RowNo].Value = 0;
// grdFares.Rows[i].Cells[COLS.OrignTypeId].Value = list[i].OriginLocationTypeId;
// grdFares.Rows[i].Cells[COLS.DestinationTypeId].Value = list[i].DestinationLocationTypeId;
grdFares.Rows[i].Cells[COLS.VehicleType].Value = list[i].ItemArray[2].ToString();
grdFares.Rows[i].Cells[COLS.VehicleId].Value = list[i].ItemArray[11].ToString();
}
}));
}

Need help C# id manager not working when run asynchronously

I have written a id manager for a xml repository. The repository manages entries in the xml file and assigns unique id (integers) to each entry that is added. The same way databases auto assign new id's to entries added to a table.
The repository will be called asynchronously so I need the id manager to be thread safe. I am using the C# lock statement but it does not seem to help. My unit tests succeed in single threaded execution but fail when run in parallel ( IE: Task ). Specifically they only fail with large sets of parallel tasks above 1000+ and even only then they only fail every other time.
The exception states that it expected 10000 but got 9998. The exception is always the same having to do with 2 missing id that were not registered.
What the heck am I missing?
ID Manager code and unit tests are provided below. The id manager utilizes Linq and is thus not very performance oriented with large sets of id's. Unit Tests TestAsyncRegistration and TestAsyncRandomRegistration are the tests that throw the exceptions.
public class IdManager
{
private List<int> idList = new List<int>();
private List<int> availableList = new List<int>();
private int nextId;
private int bufferCount;
object obj = new object();
public ReadOnlyCollection<int> RegisteredIds
{
get
{
return new ReadOnlyCollection<int>(this.idList);
}
}
public int BufferCount
{
get
{
return this.bufferCount;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("value");
}
this.bufferCount = value;
}
}
public IdManager(int bufferCount)
{
this.BufferCount = bufferCount;
this.Reset();
}
public IdManager()
: this(1000)
{
}
public void RegisterId(int id)
{
this.RegisterId(new[] { id });
}
public void Reset()
{
lock (this.obj)
{
this.availableList.Clear();
this.idList.Clear();
for (var i = 0; i < this.bufferCount; i++)
{
this.availableList.Add(i);
}
}
}
public void RegisterId(IEnumerable<int> ids)
{
lock (this.obj)
{
var distinct = ids.Except(this.idList);
this.idList.AddRange(distinct);
this.availableList = this.availableList.Except(this.idList).ToList();
}
}
public int NewId()
{
lock (this.obj)
{
if (this.availableList.Count > 0)
{
var item = this.availableList[0];
this.availableList.RemoveAt(0);
this.idList.Add(item);
return item;
}
var max = this.idList.Max();
for (var i = 1; i < this.bufferCount; i++)
{
this.availableList.Add(max + i);
}
this.availableList = this.availableList.Except(this.idList).ToList();
return this.NewId();
}
}
}
... and the unit test code ...
[TestClass]
public class IdManagerTests
{
[TestMethod]
public void TestSequence()
{
var manager = new IdManager(5);
for (var i = 0; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBrokenSequence()
{
var manager = new IdManager(5);
manager.RegisterId(1);
Assert.AreEqual(0, manager.NewId());
Assert.AreEqual(2, manager.NewId());
for (var i = 3; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestForwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(0);
manager.RegisterId(1);
manager.RegisterId(2);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBackwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(2);
manager.RegisterId(1);
manager.RegisterId(0);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public async Task TestLargeNumbersRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
manager.RegisterId(idValue++);
}
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRandomRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
// randomize the order of the id's in the list
var random = new Random((int)DateTime.Now.Ticks);
var randomizedList = from item in list
orderby random.Next()
select item;
var manager = new IdManager(1000);
manager.RegisterId(randomizedList);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
}
Your problem is in your test, not the method that you're testing, specifically the snippet:
Task.Factory.StartNew(() => manager.RegisterId(idValue++));
You're calling idValue++ from a bunch of different threads simultaneously. That's not a safe operation to perform. Either increment idValue outside of StartNew and pass in the already incremented value, or use Interlocked.Increment to handle it safely.

Is it cheaper to get a specific StackFrame instead of StackTrace.GetFrame?

If I'm simply going to do the following to see what called me,
var st = new StackTrace();
var callingMethod = st.GetFrame(1).GetMethod()
would it be cheaper to just get that specific frame?
var sf = new StackFrame(1);
var callingMethod = sf.GetMethod()
I tested with the code below, but I'm unsure if my methods are sound.
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
var method = new StackFrame(1, false);
}
sw.Stop();
Trace.WriteLine(sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
var method = new StackTrace().GetFrame(1);
}
sw.Stop();
Trace.WriteLine(sw.ElapsedMilliseconds);
// Results
// StackFrame: 850
// StackTrace: 1334
Is my approach (and results) correct?
Edit
I'd use the Caller Information attributes, however, I'm stuck in .NET 3.5 for the time being.
See recommendations for the compilation the correct benchmark. You should use prime number of iterations (for suppress JIT Loop unwinding optimization), run benchmark in Release mode without debugging, use cache warmup, etc.
I added your example in BenchmarkDotNet, look to StackFrameProgram.cs:
public class StackFrameProgram
{
private const int IterationCount = 100001;
public void Run()
{
var competition = new BenchmarkCompetition();
competition.AddTask("StackFrame", () => StackFrame());
competition.AddTask("StackTrace", () => StackTrace());
competition.Run();
}
private StackFrame StackFrame()
{
StackFrame method = null;
for (int i = 0; i < IterationCount; i++)
method = new StackFrame(1, false);
return method;
}
private StackFrame StackTrace()
{
StackFrame method = null;
for (int i = 0; i < IterationCount; i++)
method = new StackTrace().GetFrame(1);
return method;
}
}
There is my result (Intel Core i7-3632QM CPU 2.20GHz):
x86, .NET 3.5:
StackFrame : 1035ms
StackTrace : 1619ms
x64, .NET 3.5:
StackFrame : 981ms
StackTrace : 1754ms
x86, .NET 4.0:
StackFrame : 735ms
StackTrace : 1150ms
x64, .NET 4.0:
StackFrame : 637ms
StackTrace : 880ms
Let's look inside:
public StackFrame.ctor(int skipFrames, bool fNeedFileInfo)
{
this.InitMembers();
this.BuildStackFrame(skipFrames, fNeedFileInfo);
}
private void StackFrame.BuildStackFrame(int skipFrames, bool fNeedFileInfo)
{
StackFrameHelper sfh = new StackFrameHelper(fNeedFileInfo, null);
StackTrace.GetStackFramesInternal(sfh, 0, null);
int numberOfFrames = sfh.GetNumberOfFrames();
skipFrames += StackTrace.CalculateFramesToSkip(sfh, numberOfFrames);
if ((numberOfFrames - skipFrames) > 0)
{
this.method = sfh.GetMethodBase(skipFrames);
this.offset = sfh.GetOffset(skipFrames);
this.ILOffset = sfh.GetILOffset(skipFrames);
if (fNeedFileInfo)
{
this.strFileName = sfh.GetFilename(skipFrames);
this.iLineNumber = sfh.GetLineNumber(skipFrames);
this.iColumnNumber = sfh.GetColumnNumber(skipFrames);
}
}
}
public StackTrace.ctor()
{
this.m_iNumOfFrames = 0;
this.m_iMethodsToSkip = 0;
this.CaptureStackTrace(0, false, null, null);
}
private void StackTrace.CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, Exception e)
{
this.m_iMethodsToSkip += iSkip;
StackFrameHelper sfh = new StackFrameHelper(fNeedFileInfo, targetThread);
GetStackFramesInternal(sfh, 0, e);
this.m_iNumOfFrames = sfh.GetNumberOfFrames();
if (this.m_iMethodsToSkip > this.m_iNumOfFrames)
{
this.m_iMethodsToSkip = this.m_iNumOfFrames;
}
if (this.m_iNumOfFrames != 0)
{
this.frames = new StackFrame[this.m_iNumOfFrames];
for (int i = 0; i < this.m_iNumOfFrames; i++)
{
bool flag = true;
bool flag2 = true;
StackFrame frame = new StackFrame(flag, flag2);
frame.SetMethodBase(sfh.GetMethodBase(i));
frame.SetOffset(sfh.GetOffset(i));
frame.SetILOffset(sfh.GetILOffset(i));
frame.SetIsLastFrameFromForeignExceptionStackTrace(sfh.IsLastFrameFromForeignExceptionStackTrace(i));
if (fNeedFileInfo)
{
frame.SetFileName(sfh.GetFilename(i));
frame.SetLineNumber(sfh.GetLineNumber(i));
frame.SetColumnNumber(sfh.GetColumnNumber(i));
}
this.frames[i] = frame;
}
if (e == null)
{
this.m_iMethodsToSkip += CalculateFramesToSkip(sfh, this.m_iNumOfFrames);
}
this.m_iNumOfFrames -= this.m_iMethodsToSkip;
if (this.m_iNumOfFrames < 0)
{
this.m_iNumOfFrames = 0;
}
}
else
{
this.frames = null;
}
}
public virtual StackFrame StackTrace.GetFrame(int index)
{
if (((this.frames != null) && (index < this.m_iNumOfFrames)) && (index >= 0))
{
return this.frames[index + this.m_iMethodsToSkip];
}
return null;
}

Categories

Resources