Reputation: 23833
I have a method that invokes a passed Func
on a background thread called TaskSpin
. This does one method at a time based on the site clicked in a DataGridView
(DGV), and it can SHOULD ONLY do one at a time. So I click on a site (a button cell in the DGV) and it run the method on that site. Now I have many sites and do not want to click and wait hundreds of times, instead I want to batch process all the sites contained in the DGV. I cannot use a straight loop to run these, i.e.
foreach (DataGridViewRow row in this.DGV)
TaskSpin(SomeMethod, SomeParameterArray);
as this returns to caller almost immediately, and will begin running the following site which is not good as they use shared files. So I need a way to queue the sites up to be execute one-by-one. I have decided to use a ConncurrentCollection - BlockingCollection
, but I am stuck. In some button click event I have
BlockingCollection<Action<object[]>> taskQueue =
new BlockingCollection<Action<object[]>>();
List<object[]> paramQueue = new List<object[]>();
foreach (DataGridViewRow row in this.DataGridViewDrg.Rows)
{
paramQueue.Add(DrgDataRowInfo(row.Index));
Action<object[]> action = new Action<object[]>(AsyncMethod);
taskQueue.Add(action);
}
int i = 0;
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
where AsyncMethod
launched a set method on the background thread using TPL.
private void AsyncMethod(object[] siteInfo)
{
TaskSpin(BuildDataForSite, siteInfo);
}
My expectation is that this would run each Action<object[]>
one after the other. But this is just freezing my application. What am I doing wrong here?
Thanks for your time.
*Edit. TaskSpin*
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
...
// Finish the processing update UI etc.
...
}
...
}
Upvotes: 1
Views: 1146
Reputation: 3
Although I am late
My solution is to use Task.Run
instead of Task.Factory.StartNew
Task.Run(() =>
{
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
});
I am posting this answer based on this article
I also was using Task.Factory.StartNew
but then it sometimes ran on my UI thread causing my app to hang. Task.Run
solved my issue.
Upvotes: 0
Reputation: 150108
The code
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
is running on your UI thread, thus causing the block.
Your requirement seems to be that you want to process a list of things, one at a time, on a non-UI thread. To accomplish that with your current code and minimal modification, you can move your foreach above into a separate thread, e.g. by creating a single Task that runs the foreach.
Task.Factory.StartNew(() =>
{
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
});
Upvotes: 3