C# question on preventing GUI from becoming sluggish when using backgroundworker/thread
I am trying to build a small application that logins into a server and gathers data from it constantly. The problem that I am having is that my GUI is slow to respond even when using either background worker or a thread. When my application tries to login into the server, I see "(Not Responding)" appear in my login form, but it logins 开发者_如何转开发in few seconds later without Windows giving the "The program has stopped responding... terminate application" dialog. When I click the start button on my application I noticed by GUI becomes very sluggish and unresponsive. I was wondering how I could improve the response time of my program. Here is the code for the Login form using a background worker and the code for my thread that gathers data from the server. I apologize for the last section of the code not being format correctly, but SO is being non-cooperative.
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
}
}
Try using BackgroundWorker for your processing - easier than handling threads yourself unless you're in the business of handling threads in a pool and you like that stuff (or you've been doing it like that since v1.0 as I have - you're just used to it that way).
I also put all my UI interactions into a background thread and marshall the calls back through to the UI thread. This article should help you out on both: Tools for Updating Windows Forms UI from Background Threads
Another test is to swap out your call to tradingDesk.Login with a simple sleep to see if that changes anything. And how's your CPU? Happen to notice if the thread or process spikes in CPU usage? Even a multi-threaded app that eats up all your CPU will stutter - Flash comes to mind - slows down my entire system even other processes.
Try setting Thread.Priority to something lower than the GUI.
Also, your thread is on the same cpu/core as the app (same process) so if it uses 100% then even with a lowered priority you might notice a difference.
There is a library I can't recall off the top of my head for parallel processing across cpus/cores - try that if priority doesn't fix it
This seems strange to me...:
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);
}
}
Seems to me that either dataThread.Start()
is a blocking call, thus causing your UI thread to stall, or it's a non-blocking call, in which case the local reference dataThread
goes out of scope almost immediately (presumably before the thread has had time to finish it's work)?
This is a perfect example of why ThreadPool exists. Please note, when you pass the delegate to the method you want threaded to the ThreadPool, the main UI thread (the one that drives the message pump) is free and clear, waiting for the next UI event. Unless you are communicating frequently with the UI thread, there should be no reason that the UI thread is bogged down to the point of becoming unresponsive.
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;
}
Note: WaitCallback delegate requires a single parameter of an object. Also, note the comment on the "lock" statement below.
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
}
}
精彩评论