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

我正在尝试构建一个小型应用程序,它登录到服务器并不断收集来自它的数据。 我遇到的问题是即使使用后台工作程序或线程,我的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 } } 

尝试使用BackgroundWorker进行处理 – 比自己处理线程更容易,除非你是在处理池中的线程并且喜欢那些东西(或者你自己以来一直这样做,因为我有 – 你’我只是习惯了这种方式)。

我还将所有UI交互放入后台线程,并将调用重新编写回UI线程。 本文将帮助您解决这两个问题: 从后台线程更新Windows窗体UI的工具

另一项测试是通过简单的睡眠将您的调用交换到tradingDesk.Login以查看是否有任何改变。 你的CPU怎么样? 是否注意到线程或进程是否在CPU使用率上出现? 即使是一个耗尽所有CPU的multithreading应用程序也会让人感到口吃 – 想到Flash – 即使是其他进程也会降低整个系统的速度。

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

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

有一个我无法回想起的库,可以跨越cpus / cores进行并行处理 – 如果优先级无法修复它,请尝试一下

这对我来说很奇怪……:

 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 (ie doesn't block)? } catch(Exception ex) { MessageBox.Show(ex.Message); } } 

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

这是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 } }