Ускорение работы программы

85
18 марта 2021, 07:00

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

Пример моего кода:

// Высчитывание формул для второй таблицы (и сразу записываем)
for (int i = 0; i < dataGridView1.RowCount - 1; i++)
{
    if (this.dataGridView2.CurrentRow != null)
    {
        dataGridView2.Rows.Add();
        //первый пример
        this.dataGridView2.Rows[i].Cells[0].Value += string.Format("{0:0.###}", Convert.ToDouble((Convert.ToDouble(dataGridView1[2, i].Value) - Convert.ToDouble(dataGridView1[2, 0].Value)) * Convert.ToDouble(textBox1.Text)));
        //второй пример
        this.dataGridView2.Rows[i].Cells[1].Value += string.Format("{0:0.#####}", Convert.ToDouble((Convert.ToDouble(dataGridView1[7, i].Value) - Convert.ToDouble(dataGridView1[7, 0].Value)) / 78));
        //делаем расчёты дополнительных величин
        double poin = Convert.ToDouble((from DataGridViewRow row in dataGridView2.Rows
                                        where row.Cells[3].FormattedValue.ToString() != string.Empty
                                        select Convert.ToDouble(row.Cells[3].FormattedValue)).Max().ToString());
    }
    else
    {
        i--;
        dataGridView2.Rows.RemoveAt(i);
        return;
    }
}

У меня есть только две идеи как ускорить код:

  • Через async/await
  • Через многопоточность

но проблема в том, что я никогда не сталкивался с этим и даже представления не имею как их сюда привинтить... В интернете я видел обучения на примере (MyWebService)

На данный момент программа виснет (если много данных обрабатывает), но при этом же процессор нагружен только на 6% (и то 3-4% это посторонние программы) и оперативная память загружается только, когда программа выполнит свою задачу.

Answer 1

Я любитель иногда пострадать... кхм... фигнёй. Поэтому держите ваш код с микрооптимизациями:

double d = Convert.ToDouble(textBox1.Text);
for (int i = 0; i < dataGridView1.RowCount - 1; i++)
{
    var cells = dataGridView2.Rows[i].Cells;
    if (dataGridView2.CurrentRow != null)
    {
        dataGridView2.Rows.Add();
        cells[0].Value +=
            ((Convert.ToDouble(dataGridView1[2, i].Value) - Convert.ToDouble(dataGridView1[2, 0].Value)) * d)
            .ToString("0.###");
        cells[1].Value +=
            ((Convert.ToDouble(dataGridView1[7, i].Value) - Convert.ToDouble(dataGridView1[7, 0].Value)) / 78)
            .ToString("0.#####");

        double poin = (from DataGridViewRow row in dataGridView2.Rows
                       where row.Cells[3].FormattedValue.ToString() != string.Empty
                       select Convert.ToDouble(row.Cells[3].FormattedValue)).Max();
    }
    else
    {
        dataGridView2.Rows.RemoveAt(i - 1);
        return;
    }
}

Что сделано: я обратил внимание, что конвертация Convert.ToDouble(textBox1.Text) выполняется многократно в цикле. Вынес это за цикл.

Ввёл переменную cells. Не ради перфоманса, а ради сокращения кода.

Убрал все лишние вызовы Convert.ToDouble. В том числе из linq-запроса.

Заменил string.Format на ToString. Метод форматирования в рантайме парсит свою строку формата и ищет места подстановки параметров. Из-за этого его производительность весьма печальна.

Примечание: у датагрида и его ячеек есть свойство DataGridViewCell.Style. Можно задать его свойство Format и не нужно будет делать форматирование в коде.

Это всё должно улучшить производительность (но совсем чуть-чуть, конечно же).

Выражение row.Cells[3].FormattedValue.ToString() != string.Empty вероятно можно заменить на row.Cells[3].FormattedValue != null. Это будет быстрее, но нужно точно знать, что там у вас может быть.

Если бы осуществлялась привязка типизированной коллекции (со свойствами типа double), то вызовы Convert.ToDouble можно было бы заменить на приведение типа:

(((double)dataGridView1[7, i].Value - (double)dataGridView1[7, 0].Value) / 78)

Это тоже было бы быстрее.

Но в любом случае, это микрооптимизации.

Применить распараллеливание к этому коду напрямую невозможно, т. к. он работает с GUI-контролами. А менять их состояние из другого потока нельзя. Ставить вызовы Control.Invoke и т. п. - убить весь эффект от параллельности.

Поэтому самый правильный выход - не работать с GUI. Как вам уже советовали в комментариях и другом ответе, храните данные в типизированных коллекцих: List<T>, например. Код сразу станет быстрее и проще, без всех этих конвертаций. И прикрутить параллельность - раз плюнуть.

Answer 2

Первое, что я бы посоветовал, это разделить логику и представление данных. Сейчас они у Вас слиты воедино (тот же dataGridViewиспользуется для хранения и манипулирования данными). Думаю, что когда визуальные компоненты будут использоваться только для отображения готовых данных Вы уже получите немалую выгоду по ресурсам.

А, дальше уже нужно смотреть вычислительную сложность алгоритма, асинхронность/распараллеливание и т.д.

слишком много данных проходит один поток данных.

. . .

У меня есть только две идеи как упростить код:

Через Async или AWait Через много поточность

И то и другое само по себе может избавить Вас от блокировки ("зависания") пользовательского интерфейса, при обработке большого объёма информации (если всё сделаете правильно). С эффективностью алгоритмов и распределением вычислений по потокам Вам нужно будет уже самому разбираться.

READ ALSO
Telegram winapi открытие канала без браузера

Telegram winapi открытие канала без браузера

Всем привет, если в браузере вставить ссылку на канал https://tme/durov, то при условии если установлен телеграм, то вы автоматически перейдете на этот...

80
Как каждую секунду вызывать метод?

Как каждую секунду вызывать метод?

В WPF/MVVM игре есть модель часов, которые изменяются каждую секундуА в другой модели описаны свойства игрока - голод и усталость

101
Как дождаться завершение анимации ? Unity

Как дождаться завершение анимации ? Unity

При выключении панели (метод Hide): включить анимацию, дождаться завершения анимации, а только потом выключать объект (методом SetActive(false))Event...

86
Interceptor и хедер запроса с фронта на Angular к беку .NET Core

Interceptor и хедер запроса с фронта на Angular к беку .NET Core

Простой контроллер на выход из учетной записи

95