C#应用程序进程在一段时间后挂起
我实现了一个简单的C#应用程序,将大约350000条记录插入数据库。这一过程过去运作良好,大约需要20分钟 我创建了一个进度条,让您大致了解记录插入的进度。当进度条达到大约75%时,它停止进度。我必须手动终止程序,因为程序似乎没有完成。如果我使用较少的数据(如10000),进度条将完成,流程也将完成。但是,当我尝试插入所有记录时,这种情况将不再发生 请注意,如果我等待更长的时间手动终止程序,将插入更多的记录。例如,如果我在15分钟后终止程序,将插入200000条记录,而如果我在20分钟后终止程序,将插入250000条记录 此程序使用单线程。在这个过程完成之前,我不能做任何其他事情。这与线程或进程有关吗 任何反馈都将不胜感激C#应用程序进程在一段时间后挂起,c#,mysql,multithreading,process,C#,Mysql,Multithreading,Process,我实现了一个简单的C#应用程序,将大约350000条记录插入数据库。这一过程过去运作良好,大约需要20分钟 我创建了一个进度条,让您大致了解记录插入的进度。当进度条达到大约75%时,它停止进度。我必须手动终止程序,因为程序似乎没有完成。如果我使用较少的数据(如10000),进度条将完成,流程也将完成。但是,当我尝试插入所有记录时,这种情况将不再发生 请注意,如果我等待更长的时间手动终止程序,将插入更多的记录。例如,如果我在15分钟后终止程序,将插入200000条记录,而如果我在20分钟后终止程序
谢谢。令人惊讶的是,你的进度条居然能正常工作。如果不使用单独的线程,则长时间运行的任务将停止消息循环的运行,从而导致应用程序无响应 您应该使用一个。将长时间运行的代码放入事件的处理程序中。用于更新进度条。不要直接从DoWork处理程序内部访问表单控件 这里有一些如何在MSDN上执行此操作的示例
另外,请确保不要为每一个更改更新进度条。例如,如果您有100000条记录,则每100条或1000条记录只更新一次进度条。太多的事件也会导致程序停止响应。在插入过程中如何处理异常
您正在插入什么类型的数据?它是否会生成异常?您应该在单独的线程上运行插入,并选择取消操作(而不是强制关闭)。正如@Mark所建议的,使用BackgroundWorker之类的工具,或者只创建一个单独的线程并记下它。似乎流程在某个时候遇到了瓶颈,您也许应该考虑做一些日志记录。与进度无关,但您是否正在提交批量插入?这可能会大大加快流程(并减少资源消耗)。事实:
- 您声明它挂起,而在挂起几行之后,您声明应用程序仍在处理某些内容,并且您越晚终止它,在它被终止之前实际处理的项目就越多李>
- 您是否正在关闭/处理所有不再需要的数据库连接?未加密的数据库连接可能会造成巨大的内存泄漏并挂起应用程序
- 您是否尝试过在内存/性能分析器中运行应用程序?(蚂蚁很棒)
- 您是否尝试过在一段时间后将调试器附加到应用程序,以查看它挂起的确切位置以及是否挂起
private delegate void UpdateProgressBarDelegate();
private void UpdateProgressBar()
{
if (this.progressBar1.InvokeRequired)
{
this.progressBar1.Invoke(new UpdateProgressBarDelegate(UpdateProgressBar));
}
else
{
//code to update progress bar
}
}
如果需要包含任何参数,请执行以下操作:
this.progressBar1.Invoke(new UpdateProgressBarDelegate(UpdateProgressBar), param1, param2);
如果插入大量记录,请尝试使用批量复制。它将大大提高应用程序的速度。 这些函数非常简单,您可以将所有要插入的记录放在一个数据表中(使用与目标表相同的模式)并使用它调用函数 如果您懒惰,要获取datatable模式,只需执行一个类似“SELECT*FROM tableName WHERE 0=1”的查询,结果集将只包含tableName模式
private static void InsertTable(DataTable dt)
{
dt.AcceptChanges();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(System.Configuration.ConfigurationManager.ConnectionStrings["MyDB"].ToString()))
{
//Destination Table is the same as the source.
bulkCopy.DestinationTableName = dt.TableName;
try
{
// Write from the source to the destination.
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(dt);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
}
private static void InsertTableWithIdentity(DataTable dt)
{
dt.AcceptChanges();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(System.Configuration.ConfigurationManager.ConnectionStrings["MyDB"].ToString(), SqlBulkCopyOptions.KeepIdentity))
{
//Destination Table is the same as the source.
bulkCopy.DestinationTableName = dt.TableName;
try
{
// Write from the source to the destination.
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(dt);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
}
至于为什么它会变慢,很简单,查询执行所需的时间会随着记录的数量呈指数增长。因为它将数据库的未来状态存储在内存中,并且只在提交后写入(在您的情况下是在事务结束时),所以使用bulkcopy of simply put more commit。我使用线程来处理这类事情 在我的代码中的某个地方:
// Definition
private static Thread TH;
// This method starts the form that shows progress and other data
static private void Splash_MyCallBack()
{
frmLoading FL;
FL = new frmLoading();
FL.ShowDialog();
} /* Splash_MyCallBack*/
// Your process calls Splash_Stop when it is done.
static public void Splash_Stop()
{
TH.Abort();
} /* Splash_Stop*/
frmLoading执行可视化的任务,而在后台,我有一个非常处理器密集的任务。
我的流程向接口报告其进度。frmLoading实现了该接口,因此它可以知道该接口,并可以显示所需的内容(在我的示例中为2个进度条)
唯一的问题是,frmLoading必须在构造函数中包含以下内容:
Control.CheckForIllegalCrossThreadCalls= false;
在某些情况下可能会有风险(我的情况不是这样)
希望这有帮助,如果你喜欢,我可以添加更多的东西
您好,毕竟没有问题。问题是我使用的是虚拟机,因此速度有点慢。当我在Xeon服务器上运行此程序时,该过程大约在10分钟内完成。这听起来像是您的代码有问题,好像异常被悄悄地吞没了或类似的事情。你介意和我们分享代码吗?任何反馈都将不胜感激。。。同样,如果不是出于那些花时间提供建议的人的好奇心,至少对其他面临类似问题的人来说也是如此。应用程序是单线程的,这个问题到底与多线程问题有什么关系?@Jorge,如果应用程序是单线程的,插入代码将占用所有资源。因此,对UI的回调将受到限制(如果有的话)@Jorge:是的,他的应用程序是单线程的,这解释了为什么进度条不起作用。我已经更新了答案,以便更清楚地解释这一点。您如何解释只出现了挂断
Control.CheckForIllegalCrossThreadCalls= false;