C#应用程序进程在一段时间后挂起

C#应用程序进程在一段时间后挂起,c#,mysql,multithreading,process,C#,Mysql,Multithreading,Process,我实现了一个简单的C#应用程序,将大约350000条记录插入数据库。这一过程过去运作良好,大约需要20分钟 我创建了一个进度条,让您大致了解记录插入的进度。当进度条达到大约75%时,它停止进度。我必须手动终止程序,因为程序似乎没有完成。如果我使用较少的数据(如10000),进度条将完成,流程也将完成。但是,当我尝试插入所有记录时,这种情况将不再发生 请注意,如果我等待更长的时间手动终止程序,将插入更多的记录。例如,如果我在15分钟后终止程序,将插入200000条记录,而如果我在20分钟后终止程序

我实现了一个简单的C#应用程序,将大约350000条记录插入数据库。这一过程过去运作良好,大约需要20分钟

我创建了一个进度条,让您大致了解记录插入的进度。当进度条达到大约75%时,它停止进度。我必须手动终止程序,因为程序似乎没有完成。如果我使用较少的数据(如10000),进度条将完成,流程也将完成。但是,当我尝试插入所有记录时,这种情况将不再发生

请注意,如果我等待更长的时间手动终止程序,将插入更多的记录。例如,如果我在15分钟后终止程序,将插入200000条记录,而如果我在20分钟后终止程序,将插入250000条记录

此程序使用单线程。在这个过程完成之前,我不能做任何其他事情。这与线程或进程有关吗

任何反馈都将不胜感激


谢谢。

令人惊讶的是,你的进度条居然能正常工作。如果不使用单独的线程,则长时间运行的任务将停止消息循环的运行,从而导致应用程序无响应

您应该使用一个。将长时间运行的代码放入事件的处理程序中。用于更新进度条。不要直接从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;