2013-11-30 5 views
1

Я пытаюсь создать приложение Windows Forms с C#, которое считывает последовательный порт и возвращает значения в DataTable. Я создал новый поток (я попытался создать поток с потоками и BackgroundWorker), чтобы прочитать порт, а затем отобразить значения в DataTable.Скорость потока при чтении порта

Моя проблема в том, что даже без чтения порта я не могу получить более 100 значений в секунду. Вот мой код без чтения порта (только писать то же значение для каждой строки DataTable:.

namespace BackgroundWorkerExample 
{ 
    public partial class BackgroundWorkerExample : Form 
    { 
     private int counter = 0; 
     private bool threadRunning = false; 
     private DataTable dt = new DataTable(); 

     public BackgroundWorkerExample() 
     { 
      InitializeComponent(); 
     } 


     private void BackgroundWorkerExample_Load(object sender, EventArgs e) 
     { 
      //Clear DataTable 
      dt.Clear(); 

      //Add Collumns 
      dt.Columns.Add("Name"); 
      dt.Columns.Add("Value"); 
      dt.Columns.Add("Time", typeof(TimeSpan)); 


      dataGridView1.DataSource = dt; 

     } 

     private void StartButton_Click(object sender, EventArgs e) 
     { 

      threadRunning = true; 
      Thread oThread = new Thread(countUp); 
      oThread.Start(); 


     } 

     private void StopButton_Click(object sender, EventArgs e) 
     { 
      //TimerLabel.Text = timer.ToString(); 
      threadRunning = false; 
     } 


     private void countUp() 
     { 
      while (threadRunning) 
      { 
       DataRow newRow = dt.NewRow(); 
       newRow["Name"] = counter; 
       newRow["Value"] = 5; 
       newRow["Time"] = DateTime.Now.TimeOfDay; 
       dt.Rows.Add(newRow); 

       counter++; 

      } 

     } 


    } 
} 

Здесь метод countUp выполняется в отдельном потоке Если я не создаю новый поток и запустить countUp в моей основной форме нить приложение никогда не вернется, но оно намного быстрее.

+1

В будущем добавьте тег языка программирования, такой как C#, к вопросам, содержащим/о коде. Это поможет людям, знакомым с рассматриваемым языком программирования, найти ваш вопрос. –

ответ

4

Этот тест уже сильно ошибочен, он ничего не может доказать. Элементы управления, такие как DataGridView, в корне небезопасны, вы не можете обновлять их из рабочего потока. Winforms обычно довольно хорош в том, что бросает IllegalOperationException, но работает только при непосредственном доступе к свойствам управления. или к счастью не бросает для привязки данных, как вы здесь используете.

Этот тип ошибки очень трудно диагностировать, потому что на самом деле он не так часто поступает неправильно. Обычно вы получаете сбой в работе, элемент управления не отображает строку, которую вы добавили, и вы ничего не думаете об этом. Особенно, когда вы добавляете их с высокой скоростью. Но неудачи не ограничиваются только тем, что возможен запуск взаимоблокировки. Вы, конечно, do обратите внимание, что ваш пользовательский интерфейс просто зависает. Этого просто не бывает достаточно, может быть, раз в день или неделю, никогда, когда вы отлаживаете свой код. Который также делает почти невозможным выяснить , почему ваша программа не работает.

Делать это правильно требует один из двух способов:

  • Unbind сетку, установив его свойство DataSource в нуль в потоке пользовательского интерфейса. Затем создайте таблицу данных в рабочем потоке. Затем переформатируйте сетку после завершения работника, установив DataSource в поток пользовательского интерфейса.

  • Создайте один или несколько DataRows для рабочего, добавьте их в DataTable в пользовательский интерфейс.

Для последовательного порта вы, вероятно, рассмотрите вторую пулю. Вы должны использовать Control.BeginInvoke(), чтобы обеспечить обновление в потоке пользовательского интерфейса. Чтобы сделать его работоспособным, вам необходимо убедиться, что вы вызываете поток нити как можно реже. Переключатель контекста потока довольно медленный, он обычно колеблется около половины миллисекунды. Но в значительной степени зависит от того, насколько занят поток пользовательского интерфейса. И обычно он довольно занят, пытаясь сохранить обновление сетки, когда вы бросаете в нее строки.

Одно из преимуществ заключается в том, что он должен быть таким же быстрым, как человеческий глаз. Что не очень приятно видеть быстрые обновления, все это просто превращается в размытие, когда вы делаете это быстрее, чем 20 раз в секунду. Так что вызов чаще всего - это просто потраченные циклы процессора.

Поэтому не забудьте собрать достаточное количество строк в обработчике событий DataReceived, чтобы избежать избиения потока пользовательского интерфейса с помощью микрообмена. Это почти так же дорого, как массовое обновление.Вы можете заставить его существенно упасть, хотя и маловероятно для последовательного порта, когда скорость, с которой вы создаете строки, больше, чем скорость, с которой поток пользовательского интерфейса может их добавить и нарисовать. Вы заметите, что пользовательский интерфейс больше не проявляет себя больше и не реагирует на мышь и клавиатуру. Единственное лекарство от этой неудачи - намеренно снизить скорость обновления у работника.

И не забудьте до удалить строк, как указано, нет дроссельной заслонки, которая мешает таблице данных получать неограниченное количество строк. Это будет бомбить вашу программу с помощью OOM. Потребуется некоторое время, он резко снизит скорость, и вы, вероятно, заметите, что пользовательский интерфейс сначала станет кататоническим.

Смежные вопросы