c#TaskFactory ContinueWhenAll在所有任务完成之前意外运行 [英] c# TaskFactory ContinueWhenAll unexpectedly running before all tasks complete

查看:564
本文介绍了c#TaskFactory ContinueWhenAll在所有任务完成之前意外运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a data processing program in C# (.NET 4.6.2; WinForms for the UI). I'm experiencing a strange situation where computer speed seems to be causing Task.Factory.ContinueWhenAll to run earlier than expected or some Tasks are reporting complete before actually running. As you can see below, I have a queue of up to 390 tasks, with no more than 4 in queue at once. When all tasks are complete, the status label is updated to say complete. The ScoreManager involves retrieving information from a database, performing several client-side calculations, and saving to an Excel file.

从笔记本电脑运行程序时,所有功能均按预期运行;当从功能更强大的工作站上运行时,我会遇到此问题。不幸的是,由于组织上的限制,我可能无法使工作站上的Visual Studio直接进行调试。有人知道是什么原因导致我对此进行调查吗?

When running the program from my laptop, everything functions as expected; when running from a substantially more powerful workstation, I experience this issue. Unfortunately, due to organizational limitations, I likely cannot get Visual Studio on the workstation to debug directly. Does anyone have any idea what might be causing this for me to investigate?

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);
}


推荐答案

发现状态为IsFaulted后,我添加了一些代码以向日志中添加一些异常信息( https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-programming/exception-handling-task-parallel-library )。似乎问题出在底层数据库问题中,连接池中没有足够的连接剩余(超时已到期。从池中获取连接之前已经经过了超时时间。这可能是由于所有池化连接都在使用中而最大池已发生达到最大大小。)-额外的速度使查询可以更快/更频繁地触发。不能完全确定为什么,因为我确实在use子句中包含了SqlConnection,但是正在研究这方面的一些内容。无论如何,问题显然与我上面的想法有所不同,因此将其标记为准答案。

After discovering state was IsFaulted, I added some code to add some exception information to the log (https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library). Seems the problem is an underlying database issue where there are not enough connections left in the connection pool (Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.)--the additional speed allows queries to fire more quickly/frequently. Not sure entirely why, as I do have the SqlConnection enclosed in a using clause, but investigating a few things on that front. At any rate, the problem is clearly a little different than what I thought above, so marking this quasi-answered.

这篇关于c#TaskFactory ContinueWhenAll在所有任务完成之前意外运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆