c#任务工厂在所有任务完成之前意外运行时继续

c#任务工厂在所有任务完成之前意外运行时继续,c#,multithreading,concurrency,task,C#,Multithreading,Concurrency,Task,我有一个C#格式的数据处理程序(用于用户界面的.NET4.6.2;WinForms)。我遇到了一种奇怪的情况,计算机速度似乎导致Task.Factory.Continuewhally比预期运行得更早,或者某些任务在实际运行之前报告已完成。正如您在下面看到的,我有一个最多390个任务的队列,一次队列中的任务不超过4个。所有任务完成后,状态标签将更新为“完成”。ScoreManager涉及从数据库检索信息、执行多个客户端计算以及保存到Excel文件 在我的笔记本电脑上运行程序时,一切都按预期运行;当

我有一个C#格式的数据处理程序(用于用户界面的.NET4.6.2;WinForms)。我遇到了一种奇怪的情况,计算机速度似乎导致Task.Factory.Continuewhally比预期运行得更早,或者某些任务在实际运行之前报告已完成。正如您在下面看到的,我有一个最多390个任务的队列,一次队列中的任务不超过4个。所有任务完成后,状态标签将更新为“完成”。ScoreManager涉及从数据库检索信息、执行多个客户端计算以及保存到Excel文件

在我的笔记本电脑上运行程序时,一切都按预期运行;当在功能更强大的工作站上运行时,我遇到了这个问题。不幸的是,由于组织限制,我可能无法让工作站上的Visual Studio直接进行调试。有人知道是什么原因让我去调查吗

private void button1_Click(object sender, EventArgs e)
{
    int startingIndex = cbStarting.SelectedIndex;
    int endingIndex = cbEnding.SelectedIndex;
    lblStatus.Text = "Running";
    if (endingIndex < startingIndex)
    {
        MessageBox.Show("Ending must be further down the list than starting.");
        return;
    }
    List<string> lItems = new List<string>();
    for (int i = startingIndex; i <= endingIndex; i++)
    {
        lItems.Add(cbStarting.Items[i].ToString());
    }

    System.IO.Directory.CreateDirectory(cbMonth.SelectedItem.ToString());

    ThreadPool.SetMaxThreads(4, 4);
    List<Task<ScoreResult>> tasks = new List<Task<ScoreResult>>();
    for (int i = startingIndex; i <= endingIndex; i++)
    {
        ScoreManager sm = new ScoreManager(cbStarting.Items[i].ToString(),
            cbMonth.SelectedItem.ToString());
        Task<ScoreResult> task = Task.Factory.StartNew<ScoreResult>((manager) =>
            ((ScoreManager)manager).Execute(), sm);
        sm = null;
        Action<Task<ScoreResult>> itemcomplete = ((_task) =>
        {
            if (_task.Result.errors.Count > 0)
            {
                txtLog.Invoke((MethodInvoker)delegate
                {
                    txtLog.AppendText("Item " + _task.Result.itemdetail +
                        " had errors/warnings:" + Environment.NewLine);
                });

                foreach (ErrorMessage error in _task.Result.errors)
                {
                    txtLog.Invoke((MethodInvoker)delegate
                    {
                        txtLog.AppendText("\t" + error.ErrorText +
                            Environment.NewLine);
                    });
                }
            }
            else
            {
                txtLog.Invoke((MethodInvoker)delegate
                {
                    txtLog.AppendText("Item " + _task.Result.itemdetail +
                     " succeeded." + Environment.NewLine);
                });

            }
        });
        task.ContinueWith(itemcomplete);
        tasks.Add(task);
    }
    Action<Task[]> allComplete = ((_tasks) =>
    {
        lblStatus.Invoke((MethodInvoker)delegate
        {
            lblStatus.Text = "Complete";
        });
    });
    Task.Factory.ContinueWhenAll<ScoreResult>(tasks.ToArray(), allComplete);
}
private void按钮1\u单击(对象发送者,事件参数e)
{
int startingIndex=cbStarting.SelectedIndex;
int-endingIndex=cbend.SelectedIndex;
lblStatus.Text=“正在运行”;
if(结束索引<开始索引)
{
Show(“结束必须比开始在列表中靠下一步”);
返回;
}
List lItems=新列表();
对于(int i=起始索引;i
{
如果(_task.Result.errors.Count>0)
{
调用((MethodInvoker)委托
{
txtLog.AppendText(“项”+_task.Result.itemdetail+
“有错误/警告:”+Environment.NewLine);
});
foreach(错误消息错误在_task.Result.errors中)
{
调用((MethodInvoker)委托
{
txtLog.AppendText(“\t”+error.ErrorText+
环境(新线),;
});
}
}
其他的
{
调用((MethodInvoker)委托
{
txtLog.AppendText(“项”+_task.Result.itemdetail+
“成功。”+Environment.NewLine);
});
}
});
任务。继续(项目完成);
任务。添加(任务);
}
操作全部完成=(_任务)=>
{
lblStatus.Invoke((MethodInvoker)委托
{
lblStatus.Text=“完成”;
});
});
Task.Factory.continuewhall(tasks.ToArray(),all complete);
}

您正在创建一个不用等待或观察的任务,这里:

task.ContinueWith(itemcomplete);
tasks.Add(task);
Task.Factory.ContinueWhenAll<ScoreResult>(tasks.ToArray(), allComplete);
作为旁注,如果您使用
ContinueWith
Invoke((MethodInvoker)
技术,而不是旧式的
ContinueWith,您可以使代码大小减半,可读性大大提高


另外:设置
线程池
线程数的上限以控制并行度是极不可取的:

ThreadPool.SetMaxThreads(4, 4); // Don't do this!

您可以改为使用该类。它允许非常轻松地控制。在发现状态为IsFaulted后,我添加了一些代码以向日志()添加一些异常信息。问题似乎是连接池中没有足够的连接的基础数据库问题(超时已过期。从池中获取连接之前已过超时时间。发生这种情况可能是因为所有池连接都在使用,并且已达到最大池大小。)--额外的速度允许查询更快/更频繁地启动。我不确定原因,因为我确实在using子句中包含了SqlConnection,但在这方面做了一些调查。无论如何,问题显然与我上面所想的略有不同,因此标记此准答案。

我们看到的是c是否让您这么想?程序停止处理(通过任务管理器使用情况确认为0,不再创建日志条目,也不再创建输出文件)并在处理约1/3的条目后将状态更新为“完成”。它似乎总是与处理莫名其妙地停止前处理的最后一个条目相同,并显示“完成”当然,我刚刚说过,在我的一次新尝试中,我至少通过向日志中添加一些任务状态信息来获取一些信息,它已经成功地通过了它以前停止的项目。它似乎在另一个项目上不久后停止了;有了这一点,我能够看到许多任务显示为“故障”你能补充一下吗?谢谢你的建议!我现在还不太熟悉async/Wait,无法在我需要的时间范围内以我需要的方式得到一些可行的东西--我花了一些时间(没有成功)早些尝试并解决了这个问题。老实说,我的.NET背景实际上超过了2.0天,所以即使是任务的整个概念也与我习惯的有点不同:D将调查将ContinueWith分配给任务,而不是使用先行项。(另外,响应为+1,但b/c我的代表太低,我猜不会显示)@ww2406是的,我也不建议在不了解其机制的情况下跳上async Wait马车,因为尽管它表面上很简单,但它可能相当棘手。但它肯定是当今非常重要的技术。
ThreadPool.SetMaxThreads(4, 4); // Don't do this!