17 / 17 / 2
Регистрация: 11.03.2014
Сообщений: 48
1

Ускорить обработку строк файла в программе. Строк может быть огромное количество

25.04.2014, 13:26. Показов 1145. Ответов 10
Метки нет (Все метки)

Здравствуйте, уважаемые обитатели форума! Перейду сразу к делу. Итак, есть небольшая часть программы, которая данные из текстовика переносит в ДатаГрид. В текстовике может быть немерянно строк, хоть полмиллиона, поэтому было решено использовать BackGroundWorker. Собственно в каждой строке нужные мне части разделены пробелами, при этом некоторые части могут отсутствовать (если таковые имеются - заменяются пробелами). Вот код:
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Public Class Form1
    Dim a() As String
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim ofd As New OpenFileDialog
        Try
            ofd.ShowDialog()
            If Windows.Forms.DialogResult.Cancel = True Then
                Me.Close()
            End If
            a = IO.File.ReadAllLines(ofd.FileName, System.Text.Encoding.GetEncoding(866))
            Button2.Enabled = True
            Button1.Enabled = False
            Timer1.Start()
        Catch ex As Exception
        End Try
        If BackgroundWorker1.IsBusy <> True Then
            BackgroundWorker1.RunWorkerAsync()
        End If
    End Sub
    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Try
            TextBox1.Text = a.Length
            For i As Integer = 0 To a.Length - 1
            DataGridView1.Rows.Add(a(i).Chars(3), a(i).Chars(5), a(i).Chars(7) & a(i).Chars(8) & a(i).Chars(9) & a(i).Chars(10), a(i).Chars(12) & a(i).Chars(13) & a(i).Chars(14) & a(i).Chars(15) & a(i).Chars(16) & a(i).Chars(17), a(i).Remove(0, 19))
            ProgressBar1.Maximum = a.Length
            ProgressBar1.Value += 1
            Application.DoEvents()
            TextBox2.Text = DataGridView1.Rows.Count - 1
            Next
        Catch ex As Exception
        End Try
    End Sub
End Class
скорость работы не радует - на добавление тысячи записей требуется в среднем 11 секунд, т. е. почти 20 минут на 100 К строк. вычитал где-то что, мол, использование переменных типа char и string прошлый век, и намного быстрее использовать класс system.text.stringbuilder. Вдохновился прочитанным, заменил
VB.NET
1
DataGridView1.Rows.Add(a(i).Chars(3), a(i).Chars(5), a(i).Chars(7) & a(i).Chars(8) & a(i).Chars(9) & a(i).Chars(10), a(i).Chars(12) & a(i).Chars(13) & a(i).Chars(14) & a(i).Chars(15) & a(i).Chars(16) & a(i).Chars(17), a(i).Remove(0, 19))
на
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 Dim v As New System.Text.StringBuilder(a(i))
             v.Remove(0, 3)
             b(i) = v.ToString
             Dim liter As New System.Text.StringBuilder(b(i))
             liter.Remove(1, liter.Length - 1)
             
                Dim sex As New System.Text.StringBuilder(b(i))
                sex.Remove(3, sex.Length - 3)
                sex.Remove(0, 2)
                
               Dim gr As New System.Text.StringBuilder(b(i))
               gr.Remove(8, gr.Length - 8)
               gr.Remove(0, 4)
              
                Dim dr As New System.Text.StringBuilder(b(i))
                dr.Remove(15, dr.Length - 15)
                dr.Remove(0, 9)
              
               DataGridView1.Rows.Add(liter, sex, gr, dr, ik)
и ничего не изменилось - скорость прежняя.
Все ли я делаю правильно и есть ли действенный способ ускорить это безобразие? Заранее спасибо за ответ!
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.04.2014, 13:26
Ответы с готовыми решениями:

На сайт поступает огромное количество запросов? В чём может быть причина?
Всем доброго времени суток. В общем ситуация следуюущая: Сайт, который работал на движке Joomla 2.5...

Хэш функция строк (строк в массиве может быть около 2 миллионов)
Подскажите пожалуйста алгоритм хэш функции для строк , строк в массиве может быть около 2...

Порядок строк в файле g должен быть обратимым в отношении порядка строк файла f
Дан текстовый файл f. Записать строки файла f в файл g. Порядок строк в файле g должен быть...

Создать массив размерностью которых должно быть количество строк и столбцов по данным из файла
Добрый вечер, переделываю программу с С++ на C# и возникли трудности с массивами может ли кто то...

10
1480 / 575 / 106
Регистрация: 26.03.2012
Сообщений: 1,015
25.04.2014, 16:36 2
Visual Basic
1
Application.DoEvents()
замени на
VB.NET
1
2
3
if i mod 100 = 0 then
Application.DoEvents()
end if
еще можно добавить газу если перед добавлении первой строки, скрыть таблицу, и показать после добавления последней строки
1
3975 / 3174 / 762
Регистрация: 02.02.2013
Сообщений: 3,044
Записей в блоге: 2
25.04.2014, 16:39 3
Очевидно, что оптимизировать нужно цикл по i в RunWorkerCompleted и по возможности убрать из него все лишнее. Для сравнительной оценки различных вариантов сформировал небольшую тестовую программу.
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim ss As String = "asdfghjklzxcvbnqwertyui2345678yhbvgtrfvcfr"
    Dim tt As New Stopwatch
    Dim rr(10001) As String
    Dim cc() As Char
    DataGridView1.Rows.Clear()
    tt.Start()
    For i = 0 To 10000
        'вариант 1
        'DataGridView1.Rows.Add(ss.Chars(2), ss.Chars(4), ss.Chars(6) & ss.Chars(7) & ss.Chars(8) & ss.Chars(9) & ss.Chars(10), ss.Chars(12), ss.Chars(14) & ss.Chars(15) & ss.Chars(16) & ss.Chars(17) & ss.Chars(18), ss.Chars(20))
        'вариант 2
        'cc = ss.ToCharArray
        'DataGridView1.Rows.Add(cc(2), cc(4), cc(6) & cc(7) & cc(8) & cc(9) & cc(10), cc(12), cc(14) & cc(15) & cc(16) & cc(17) & cc(18), cc(20))
        'вариант 3
        DataGridView1.Rows.Add(ss.Chars(2), ss.Chars(4), ss.Substring(6, 5), ss.Chars(12), ss.Substring(14, 5), ss.Chars(20))
        'TextBox1.Text = DataGridView1.Rows.Count - 1
        'ProgressBar1.Maximum = rr.Length
        'ProgressBar1.Value += 1
        'Application.DoEvents()
    Next
    tt.Stop()
    MsgBox("Time (ms) = " & tt.ElapsedMilliseconds)
End Sub
Получил следующие результаты (мс):
Вариант 1: 1381
Вариант 2: 1416
Вариант 3: 1333
+ TextBox1 1712
+ ProgressBar1 3365

Использование StringBuilder здесь мало что даст. Как известно при изменении строки строка как таковая не изменяется а создается новый объект типа String. Именно в этих случаях и используют StringBuilder который можно представить в виде буфера способного увеличиваться в размерах.
1
1480 / 575 / 106
Регистрация: 26.03.2012
Сообщений: 1,015
25.04.2014, 16:53 4
ovva,
VB.NET
1
Application.DoEvents()
по любому надо оставить, а то пользователю покажется что программа зависла (или винда может выкинуть окошко типа "эта программа не отвечает") т.к.
Цитата Сообщение от Евстефеич Посмотреть сообщение
немерянно строк, хоть полмиллиона
просто вызывать его надо не при каждой интерации а через 100 или больше

Добавлено через 3 минуты
Евстефеич, еще заметил
VB.NET
1
ProgressBar1.Maximum = a.Length
поставь перед for, а не внутри него

Добавлено через 2 минуты
Примерно так:
VB.NET
1
2
3
4
5
6
7
8
9
            ProgressBar1.Maximum = a.Length
            For i As Integer = 0 To a.Length - 1
              DataGridView1.Rows.Add(a(i).Chars(3), a(i).Chars(5), a(i).Chars(7) & a(i).Chars(8) & a(i).Chars(9) & a(i).Chars(10), a(i).Chars(12) & a(i).Chars(13) & a(i).Chars(14) & a(i).Chars(15) & a(i).Chars(16) & a(i).Chars(17), a(i).Remove(0, 19))
              If I mod 100 = 0 then
                ProgressBar1.Value = I
                TextBox2.Text = I
                Application.DoEvents()
              end if
            Next
1
17 / 17 / 2
Регистрация: 11.03.2014
Сообщений: 48
25.04.2014, 17:01  [ТС] 5
ребят, большое спасибо! позже проверю - отпишусь!
PAnT0P, я правильно понял, что в твоем случае через каждые 100 записей будет происходить сдвиг шкалы прогрессбара?
0
3975 / 3174 / 762
Регистрация: 02.02.2013
Сообщений: 3,044
Записей в блоге: 2
25.04.2014, 17:09 6
Я лишь предлагал почистить цикл.
Возник вопрос, а какая собственно операция выполняется в фоновом режиме? Событие BackgroundWorker.RunWorkerCompleted возникает, когда выполнение фоновой операции завершено.
1
17 / 17 / 2
Регистрация: 11.03.2014
Сообщений: 48
25.04.2014, 17:19  [ТС] 7
ovva, как ни странно - никакая. я это уже понял,когда создал пост. просто без backgroundworker программа висла намертво, после его добавления и пары строк сопутствующего кода - программа перестала вылетать. все дело в application.doEvents, я его в первоначальном варианте без backgroundworker забыл написать.такие дела
0
3975 / 3174 / 762
Регистрация: 02.02.2013
Сообщений: 3,044
Записей в блоге: 2
25.04.2014, 21:04 8
Лучший ответ Сообщение было отмечено Евстефеич как решение

Решение

Вариант с использованием BackgroundWorker.
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    Dim tm As New Stopwatch
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'здесь можно определить имя файла и передать его как параметр RunWorkerAsync
        Dim fPath As String = ""
        BackgroundWorker1.RunWorkerAsync(fPath)
        tm.Start()
    End Sub
    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        'имя файла
        Dim fPath As String = CType(e.Argument, String)
        'имитация считывания строк файла
        Dim ss As String = "asdfghjklzxcvbnqwertyui2345678yhbvgtrfvcfr"
        Dim dv(10000) As DataGridViewRow
        Dim DGV As New DataGridView
        DGV.ColumnCount = 6
        DGV.Columns(0).Name = "Col1"
        DGV.Columns(1).Name = "Col2"
        DGV.Columns(2).Name = "Col3"
        DGV.Columns(3).Name = "Col4"
        DGV.Columns(4).Name = "Col5"
        DGV.Columns(5).Name = "Col6"
        Dim str(5) As String
        For i = 0 To 10000
            str(0) = ss.Chars(2)
            str(1) = ss.Chars(4)
            str(2) = ss.Chars(6)
            str(3) = ss.Substring(6, 5)
            str(4) = ss.Substring(14, 5)
            str(5) = ss.Chars(20)
            dv(i) = New DataGridViewRow
            dv(i).CreateCells(DGV)
            dv(i).SetValues(str)
        Next
        e.Result = dv
    End Sub
    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerComplet
        DataGridView1.Rows.Clear()
        DataGridView1.Rows.AddRange(CType(e.Result, DataGridViewRow()))
        tm.Stop()
        MsgBox("Time (ms) = " & tm.ElapsedMilliseconds)
    End Sub
Плюсы:
1. Во время работы фонового процесса пользователь может продолжать текущую работу
2. Кажется это более быстрый вариант
3. Остается возможность использования progressBar (ReportProgress, ProgressChanged)
1
355 / 294 / 78
Регистрация: 02.10.2013
Сообщений: 476
Записей в блоге: 5
25.04.2014, 21:43 9
По моему опыту работа напрямую с DGV медленнее, чем сохранить данных в DataTable а потом привязать к DGV
1
3975 / 3174 / 762
Регистрация: 02.02.2013
Сообщений: 3,044
Записей в блоге: 2
25.04.2014, 22:26 10
Вариант с BackgroundWorker. Для решения задачи с границей цикла 10000 затрачено 449 мс, с включением в процесс progressBar – 470 мс.
0
17 / 17 / 2
Регистрация: 11.03.2014
Сообщений: 48
26.04.2014, 17:25  [ТС] 11
ovva, вариант с backgroundworker - это нечто! 36 секунд в среднем (это еще с progressbar-ом при этом!) на добавление 220 тысяч записей! вместо >40 минут)) большое спасибо,то что нужно!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.04.2014, 17:25

Создать матрицу количество строк которой равно количеству строк файла
Здравствуйте. Хочу из файла считать данные построчно. Считаю количество строк и создаю двумерный...

Ускорить считывание большого количества строк (~2500000) из файла
в общем есть файл, в нем около 2500000 строк (в каждой строке есть всего 2 объекта), я пытаюсь...

Каким может быть максимальное число строк и столбцов матрицы
Здрасти, функция int** CreateMatrix(int count_row,int count_col) создает двумерный дин. массив, в...

Сколько строк может быть в таблице и как снять ограничение?
Загружаю файл &quot;прайс&quot; в таблицу w_prod, файл &quot;прайс&quot;- содержит 45000строк 2столбца. ЗАГРУЖАЕТСЯ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.