c#任务工厂在所有任务完成之前意外运行时继续
我有一个C#格式的数据处理程序(用于用户界面的.NET4.6.2;WinForms)。我遇到了一种奇怪的情况,计算机速度似乎导致Task.Factory.Continuewhally比预期运行得更早,或者某些任务在实际运行之前报告已完成。正如您在下面看到的,我有一个最多390个任务的队列,一次队列中的任务不超过4个。所有任务完成后,状态标签将更新为“完成”。ScoreManager涉及从数据库检索信息、执行多个客户端计算以及保存到Excel文件 在我的笔记本电脑上运行程序时,一切都按预期运行;当在功能更强大的工作站上运行时,我遇到了这个问题。不幸的是,由于组织限制,我可能无法让工作站上的Visual Studio直接进行调试。有人知道是什么原因让我去调查吗c#任务工厂在所有任务完成之前意外运行时继续,c#,multithreading,concurrency,task,C#,Multithreading,Concurrency,Task,我有一个C#格式的数据处理程序(用于用户界面的.NET4.6.2;WinForms)。我遇到了一种奇怪的情况,计算机速度似乎导致Task.Factory.Continuewhally比预期运行得更早,或者某些任务在实际运行之前报告已完成。正如您在下面看到的,我有一个最多390个任务的队列,一次队列中的任务不超过4个。所有任务完成后,状态标签将更新为“完成”。ScoreManager涉及从数据库检索信息、执行多个客户端计算以及保存到Excel文件 在我的笔记本电脑上运行程序时,一切都按预期运行;当
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!