Nano Hash - криптовалюты, майнинг, программирование

Прокрутка DataGridView, похоже, резко снижает производительность

Я пишу приложение на C # с помощью Microsoft Visual Studio 2019. Приложение взаимодействует с несколькими платами Arduino. Отправка и получение работают асинхронно с использованием модели TAP и работают нормально.

Приложение основано на приложении Windows Form с использованием .NET Framework 4.7.2. Я добавил DataGridView в форму, используя DataTable в качестве DataSource. Намерение состоит в том, чтобы использовать этот DataGridView в качестве регистратора данных, отображающего 5 столбцов: TimeStamp, DeviceID, Direction, Command и ErrorStatus.

Если я отключу DataGridView, я достигну 500 команд в секунду на китайском клоне Arduino. На реальном Arduino я, кажется, получаю только до 244 команд в секунду - см. Другой вопрос о stackoverflow ниже - но сейчас вопрос не в этом:

Скорость передачи данных через USB (ПК / Arduino) с использованием SerialPort в C # кажется, что он «зажимает»

Когда я включаю свой DataGridView, я вижу, что скорость связи падает примерно до 25 команд в секунду, и это происходит исключительно из-за обновления строк в DataGridView. Но это похоже только на тот случай, когда DataGridView начинает прокрутку.

См. Ниже фрагмент кода:

dt.Rows.Add(new string[] 
{
    DateTime.Now.ToString("HH:mm:ss:fff"),
    device._FMGSDevice,
    action,
    notifyData.Command,
    notifyData.notifyError.ToString()
});
if (dt.Rows.Count > maxLines)
    dt.Rows.RemoveAt(0);

dt - это таблица данных, которая используется в качестве источника данных для DataGridView. Для каждого сообщения в конце DataTable добавляется строка, которая затем автоматически обновляется в DataGridView.

maxLines - это константа, которая в настоящее время установлена ​​на 500. Чтобы мой DataGridView не получал слишком много строк, я ограничиваю ее до 500 строк. Если предел достигнут, я удаляю первую строку с помощью RemoveAt (0) после добавления новой строки, чтобы сохранить ее максимум на 500 строках.

Теперь я вижу, что как только DataGridView начинает прокрутку (RemoveAt (0) заставляет все строки перемещаться вверх на одну строку), скорость резко падает.

Есть ли у кого-нибудь идеи, как ускорить прокрутку? Или есть еще один элемент, который я мог бы использовать для входа в журнал? (хотя мне тоже нужна фильтрация).

28.12.2020

  • DGV не был бы моим первым выбором для реализации этой регистрации. Вы отправляете команды в ветке окна? 28.12.2020
  • возможно, вам понадобится список / таблица для хранения данных, но в сетке отображаются только 20 или 30 строк. при прокрутке то обновите сетку. 28.12.2020
  • Попробуйте DataGridView.VirtualMode и Реализация виртуального режима в элементе управления Windows Forms DataGridView 28.12.2020
  • Попробуйте DoubleBuffer DGV! 28.12.2020
  • @CaiusJard Нет, для связи используется реализация на основе асинхронных задач. 28.12.2020
  • Как уже упоминалось, используйте виртуальный режим DGV и не позволяйте элементу управления автоматически изменять размер столбцов в зависимости от содержимого (это убивает производительность): используйте столбцы с фиксированной шириной и FillWeight = 1. В качестве альтернативы используйте ListView в виртуальном режиме (пример здесь) вместо DGV: LV в виртуальном режиме быстрее, чем DGV. 28.12.2020
  • @TaW Использование DoubleBuffer дало мне увеличение производительности почти на 500% (в 5 раз). Вместо 24 команд в секунду у меня теперь 118 команд в секунду. 28.12.2020

Ответы:


1

Я точно не знаю ваше приложение, но вы можете попробовать метод удаления вместо RemoveAt и посмотреть, улучшится ли производительность. должен быть:

DataRow dr = dtName.Rows[0];
dr.Delete();
dtName.AcceptChanges();

В качестве альтернативы вы можете увеличить количество удаляемых записей, например, удалить первые 10 или 20 записей вместо только первой.

28.12.2020
  • Я попробовал оба ваших предложения. Использование Delete () и AcceptChanges вместо RemoveAt (), похоже, не приносит никакого прироста производительности. Я также пробовал использовать 10 и 20 строк одновременно, используя оба метода, и это не дало мне никаких изменений. В любом случае спасибо за отзыв, очень признателен. 28.12.2020

  • 2

    Предложение от @TaW пока работает лучше всего. По крайней мере, реализовать это было проще всего. Я еще не экспериментировал с виртуальным режимом и не пробовал ListView, потому что для их реализации требуется некоторое время.

    Я создал производный класс из DataGridView, как показано ниже (см. Ссылку, где я это нашел):

    Ужасная производительность перерисовки DataGridView на одном из двух моих экранов

    class CustomDataGridView : DataGridView
    {
        public CustomDataGridView()
        {
            // if not remote desktop session then enable double-buffering optimization
            if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
                DoubleBuffered = true;
        }
    }
    

    Поскольку я использую Designer, я вручную изменил код, чтобы вместо этого использовать класс CustomDataGridView.

    this.dgLogView = new HW_Hub.CustomDataGridView();
    

    Хотя, в чем я не уверен, можно ли изменять код в ... designer.cs? У меня такое ощущение, что Visual Studio владеет этим файлом и вносит изменения автоматически. Нужен ли мне другой способ отменить стандартную реализацию?

    28.12.2020
  • ... designer.cs? У меня такое ощущение, что этот файл принадлежит Visual Studio В некотором роде; есть раздел, который зарезервирован, но все остальное можно изменить, если вы не испортили синтаксис. Резервируемая область помечается как таковая. 28.12.2020
  • Visual Studio сериализует то, что вы добавили в конструктор формы. Если пользовательский элемент управления CustomDataGridView доступен (сериализатор может его найти), изменения, внесенные вами в файл Designer.cs, сохранятся, а элемент управления в визуальном конструкторе будет заменен. Кстати, этот способ замены Control другим довольно распространен. Предупреждение относится к коду, добавленному в designer.cs, который не подлежит сериализации: конечно, этот код не будет сохраняться, поэтому все изменения будут потеряны при срабатывании сериализатора. 28.12.2020

  • 3

    Не следует обновлять данные автоматически. Люди будут читать данные, возможно, выбирать их части. Это довольно неприятно, если данные, которые вы только что выбрали, прокручиваются.

    Это похоже на редактирование документа: части, которые вы читаете или только что выбрали, внезапно исчезнут.

    Добавьте кнопку «Обновить», которая обновит данные.

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

    Что-то вроде этого:

    // the data in one Row:
    class ArduinoLogData
    {
        ... // properties that will be shown in the columns
    }
    
    BindingList<ArduinoLogData> DisplayedArduinoData
    {
        get => (BindingList<LoggedArduinoRow>)this.DataGridView1.DataSource;
        set => this.DataGridView1.DataSource = value;
    }
    
    // Fetch ArduinoData
    IEnumerable<ArduinoLogData> FetchArduinoLogdata()
    {
        ...
    }
    

    Подумайте о создании перегрузки, в которой вы указываете, какие ардуины должны быть получены, чтобы вы могли обновлять только те ардуины, которые в настоящее время видны. Используйте DataGridViewRow.Displayed, чтобы получить данные ArduinoLogData, которые отображаются в данный момент:

    IEnumerable<ArduinoLogData> DisplayedData => this.DataGridView1.Rows
        .Where(row => row.Displayed)
        .Select(row => row.DataBoundItem)
        .Cast<ArduinoLogData>();
    

    И способ:

    void RefreshArduinoLogData(ICollection<ArduinoLogData> itemsToRefresh)
    {
        ... // update only these items.
    }
    
    void RefreshDisplayedArduinoLogData()
    {
        this.RefreshArduinoLogData(this.DisplayedData.ToList());
    }
    

    Это обновит только видимые элементы, около 40 строк или около того.

    Делайте это раз в секунду:

    Timer refreshTime = new Timer
    {
        AutoReset = true,
        Interval = TimeSpan.FromSeconds(1).TotalMilliseconds,
    };
    timer.Elapsed += OnTimerTick;
    timer.Enabled = true;
    
    void OnTimerTick(object sender, ...)
    {
        this.RefreshDisplayedArduinoLogData();
    }
    

    Не забудьте удалить свой таймер при закрытии формы или, наконец, при удалении формы.

    18.01.2021
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..