First about my goal:
I am importing a table with about 1000-5000 rows to a DataTable
. This one is bound to a DataGridView
. Now for every row there has to run a process that takes about 5-10 seconds. After a single process finished I want to write back the result to the DataTabel
(result-column).
Because this process is independent I want to use multithreading to speed it up.
This is an example structure of my current code:
// Will be created for each row
public class FooObject
{
public int RowIndex;
public string Name;
//...
}
// Limiting running tasks to 50
private Semaphore semaphore = new Semaphore(50, 50);
// The DataTable is set up at start-up of the App (columns etc)
private DataTable DtData { get; set; } = new DataTable();
// The button that starts the process
private void btnStartLongRun(object sender, EventArgs e)
{
// some init-stuff
StartRun();
}
private async void StartRun()
{
for (int rowIndex = 0; rowIndex < DtData.Rows.Count)
{
// Creating a task to not block the UI
// Using semaphore here to not create objects
// for all lines before they get in use.
// Having this inside the real task it consumed
// a lot of ram (> 1GB)
await Task.Factory.StartNew(() =>
{
semaphore.WaitOne();
});
// The row to process
var currentRow = DtData.Rows[rowIndex];
// Creating an object from the row-data
FooObject foo = new FooObject()
{
RowIndex = rowIndex;
Name = currentRow["Name"].ToString();
}
// Not awaiting because I want multiple threads
// to run at the same time. The semaphore is
// handling this
TaskScheduler scheduler = TaskScheduler.Current;
Task.Factory.StartNew(() =>
{
// Per-row process
return ProcessFoo(foo);
}).ContinueWith((result) =>
{
FinishProcessFoo(result.Result);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
}
}
private FooObject ProcessFoo(FooObject foo)
{
// the actual big process per line
}
private void FinishProcessFoo(FooObject foo)
{
// Locking here because I got broken index errors without
lock(DtGrid.Rows.SyncRoot)
{
// Getting the row that got processed
var procRow = DtData.Rows[foo.RowIndex];
// Writing the result to that row
procRow["Result"] = foo.Result;
// Raising the progressbar
pbData.Value++;
}
// Letting the next task start.
semaphore.Release();
}
The big problem:
In the beginning everything is working fine. All threads are running smooth and doing their job. But as longer the app runs, as more it is getting unresponsive. It looks like the app is slowly starting to block more and more.
I started a test-run with 5000 rows. It got in stuck at around row 2000. Sometimes even an error raises that the app isn't responding
.
I haven't got a lot experience in multi threading. So maybe this code is totally bad. I appreciate every help in here. I would also be happy about pointing me into another direction to get this running better.
Thank you very much.
Edit
If there is anything I can debug to help in here just tell me.
Edit 2
I already enabled all Common Language Runtime Exceptions
to check if there is anything that's not raising an error. Nothing.