我有一个方法在名为Func
的后台线程上调用传递的TaskSpin
。这基于DataGridView
(DGV)中点击的站点一次执行一种方法,并且它一次只能做一个。所以我点击一个站点(DGV中的一个按钮单元格),然后在该站点上运行该方法。现在我有很多站点,不想点击并等待数百次,而是我想批量处理DGV中包含的所有站点。我不能使用直接循环来运行这些,即
foreach (DataGridViewRow row in this.DGV)
TaskSpin(SomeMethod, SomeParameterArray);
因为这几乎立即返回到调用者,并且将开始运行以下站点,这不好,因为他们使用共享文件。所以我需要一种方法来排队网站,逐个执行。我决定使用ConncurrentCollection - BlockingCollection
,但我被困住了。在某些按钮点击事件中,我有
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]);
其中AsyncMethod
使用TPL在后台线程上启动了set方法。
private void AsyncMethod(object[] siteInfo)
{
TaskSpin(BuildDataForSite, siteInfo);
}
我的期望是,每个Action<object[]>
一个接一个地运行。但这只是冻结我的申请。我在这里做错了什么?
感谢您的时间。
* 编辑。 TaskSpin *
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
...
// Finish the processing update UI etc.
...
}
...
}
答案 0 :(得分:3)
代码
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
正在您的UI线程上运行,从而导致阻止。
您的要求似乎是您希望在非UI线程上一次处理一个事物列表。要使用当前代码和最少的修改来实现这一目标,您可以将上面的 foreach 移动到一个单独的线程中,例如通过创建运行 foreach 的单个任务。
Task.Factory.StartNew(() =>
{
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
});
答案 1 :(得分:0)
虽然我迟到了
我的解决方案是使用Task.Run
代替Task.Factory.StartNew
Task.Run(() =>
{
foreach (Action<object[]> action in taskQueue.GetConsumingEnumerable())
action(paramQueue[i]);
});
我正在根据此article
发布此答案我也使用Task.Factory.StartNew
,但是有时它在我的UI线程上运行,导致我的应用程序挂起。 Task.Run
解决了我的问题。