关于使用backgroundworker / thread时防止GUI变得迟缓的C#问题

时间:2010-02-12 04:03:08

标签: c# multithreading backgroundworker

我正在尝试构建一个小型应用程序,它可以登录到服务器并不断地从中收集数据。我遇到的问题是即使使用后台工作程序或线程,我的GUI响应也很慢。当我的应用程序尝试登录到服务器时,我看到“(无响应)”出现在我的登录表单中,但它在几秒钟后登录而没有Windows给出“程序已停止响应...终止应用程序”对话框。当我点击我的应用程序上的开始按钮时,我注意到GUI变得非常缓慢且无响应。我想知道如何才能改善程序的响应时间。下面是使用后台工作程序的Login表单的代码以及从服务器收集数据的我的线程的代码。我为代码的最后一部分没有正确格式道歉,但是SO是非合作的。

    private void btnLogin_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txtAccount.Text) || string.IsNullOrEmpty(txtPassword.Text))
        {
            MessageBox.Show("Must Enter Username and Password");
            return;
        }
        btnLogin.Enabled = false;
        account = txtAccount.Text;
        password = txtPassword.Text;
        accountType = cmbAccountType.SelectedItem.ToString();
        loginBackgroundWorker.RunWorkerAsync();
    }

    private void loginBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        loginSuccess=tradingDesk.Login(account, password, accountType);
    }

    private void loginBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (loginSuccess)
        {
            this.DialogResult = DialogResult.OK;
        }
        btnLogin.Enabled = true;
    }


    private void btnStart_Click(object sender, EventArgs e)
        {
        Thread dataThread=new Thread(GetServerData);
        dataThread.IsBackground=true;

        try
        {
            dataThread.Start();
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message);
        }}

private void GetServerData()
{
    try
    {
        while (true)
        {
            lock (myLock)
            {
               //Perform Server Task with large amounts of data
            }
        }
    }
    catch
    {
        //Handle exception code
    }
}

4 个答案:

答案 0 :(得分:1)

尝试使用BackgroundWorker进行处理 - 比自己处理线程更容易,除非你处理池中的线程并且你喜欢那些东西(或者你自从v1.0以来就像这样做了) - 你只是习惯了这种方式。)

我还将所有UI交互放入后台线程,并将调用重新编写回UI线程。本文应该对您有所帮助:Tools for Updating Windows Forms UI from Background Threads

另一项测试是通过简单的睡眠将您的电话交换到tradingDesk.Login以查看是否有任何改变。你的CPU怎么样?是否注意到线程或进程是否会占用CPU使用率?即使是一个耗尽所有CPU的多线程应用程序也会让人感到口吃 - 想到Flash - 甚至会让整个系统的速度变慢。

答案 1 :(得分:0)

尝试将Thread.Priority设置为低于GUI的值。

此外,您的线程与应用程序(相同的进程)位于相同的cpu / core上,因此如果它使用100%,那么即使优先级较低,您也可能会注意到差异。

有一个我无法回想起的库,可以在cpus / cores上进行并行处理 - 如果优先级没有解决它,请尝试一下

答案 2 :(得分:0)

这对我来说很奇怪......:

private void btnStart_Click(object sender, EventArgs e)
{
    Thread dataThread = new Thread(GetServerData);  // Won't this go out of scope?
    dataThread.IsBackground = true;

    try
    {
        dataThread.Start();     // Isn't this asynchronous (i.e. doesn't block)?
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

对我来说,dataThread.Start()是一个阻塞调用,从而导致你的UI线程停止,或者它是一个非阻塞调用,在这种情况下,本地引用dataThread几乎超出了范围马上(大概是在线程有时间完成它的工作之前)?

答案 3 :(得分:0)

这是ThreadPool存在的一个很好的例子。请注意,当您将委托传递给要线程到ThreadPool的方法时,主UI线程(驱动消息泵的线程)是空闲且清晰的,等待下一个UI事件。除非您经常与UI线程进行通信,否则应该没有理由将UI线程陷入无法响应的程度。

private void btnStart_Click(object sender, EventArgs e)
{
   // spawn the GetServerData() method on the ThreadPool
   ThreadPool.QueueUserWorkItem(new WaitCallback(GetServerData));

   // after the above is called, you'll immediately get here because
   // the UI thread is free from having to process GetServerData()
   return;
}

注意:WaitCallback委托需要对象的单个参数。另外,请注意下面“锁定”声明的评论。

private void GetServerData(object o)
{
   try
   {
      while (true)
      {
         // if ANYTHING in the UI thread requires this lock (recurring timer),
         // you've just eliminated ANY benefit to having this on a separate thread
         lock (myLock)
         {
            // processor intensive code
         }
      }
   }

   catch
   {
      // handle exceptions
   }
}