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