Вопрос C # по предотвращению замедления GUI при использовании backgroundworker / thread - PullRequest
0 голосов
/ 12 февраля 2010

Я пытаюсь создать небольшое приложение, которое регистрируется на сервере и постоянно собирает с него данные. Проблема, с которой я сталкиваюсь, заключается в том, что мой графический интерфейс медленно реагирует даже при использовании фонового рабочего процесса или потока. Когда мое приложение пытается войти на сервер, в форме входа в систему появляется сообщение «(Не отвечает)», но через несколько секунд оно регистрируется, и Windows не выдает диалоговое окно «Программа перестала отвечать ... завершить приложение». Когда я нажимаю кнопку «Пуск» в своем приложении, я замечаю, что графический интерфейс пользователя становится очень вялым и не отвечает. Мне было интересно, как я могу улучшить время отклика моей программы. Вот код для формы входа в систему с использованием фонового работника и код моего потока, который собирает данные с сервера. Я извиняюсь за то, что последний раздел кода не был правильно отформатирован, но 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 ]

1 голос
/ 12 февраля 2010

Попробуйте использовать BackgroundWorker для своей обработки - проще, чем обрабатывать потоки самостоятельно, если вы не заняты обработкой потоков в пуле, и вам это нравится (или вы делали это с версии 1.0, как я - ты просто так к этому привык).

Я также помещаю все свои взаимодействия с пользовательским интерфейсом в фоновый поток и перенаправляю вызовы обратно в поток пользовательского интерфейса. Эта статья должна помочь вам обоим: Инструменты для обновления пользовательского интерфейса Windows Forms из фоновых потоков

Еще один тест - обменять ваш звонок на tradingDesk.Login простым сном, чтобы посмотреть, изменит ли это что-нибудь. А как твой процессор? Случается ли замечать, что поток или процесс резко возрастает при загрузке процессора? Даже многопоточное приложение, которое съедает весь ваш процессор, заикается - вспоминается Flash - замедляет всю мою систему, даже другие процессы.

0 голосов
/ 12 февраля 2010

Это прекрасный пример того, почему существует ThreadPool. Обратите внимание, что когда вы передаете делегата методу, который вы хотите подключить к ThreadPool, основной поток пользовательского интерфейса (тот, который управляет насосом сообщений) свободен и чист, ожидая следующего события пользовательского интерфейса. Если вы часто не общаетесь с потоком пользовательского интерфейса, не должно быть никаких причин, по которым поток пользовательского интерфейса может зависнуть до такой степени, что он перестает отвечать.

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 требуется один параметр объекта. Также обратите внимание на комментарий к заявлению «lock» ниже.

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
   }
}
0 голосов
/ 12 февраля 2010

Мне это кажется странным ...:

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() является блокирующим вызовом, в результате чего поток пользовательского интерфейса блокируется, либо это неблокирующий вызов,в этом случае локальная ссылка dataThread почти сразу выходит из области видимости (предположительно, до того, как поток успел завершить свою работу)?

0 голосов
/ 12 февраля 2010

Попробуйте установить Thread.Priority на что-то меньшее, чем GUI.

Кроме того, ваш поток находится в том же процессоре / ядре, что и приложение (тот же процесс), поэтому, если он использует 100%, даже с пониженным приоритетом вы можете заметить разницу.

Есть библиотека, которую я не могу вспомнить с головы до головы для параллельной обработки между процессорами / ядрами - попробуйте, если приоритет не исправит это

...