BlockingCollection未按预期执行

时间:2012-08-01 17:04:36

标签: c# blockingcollection

我有一个方法在名为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.
        ...
    }
    ...
}

2 个答案:

答案 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解决了我的问题。