Страница: 1 | 2 | 3 | 4 | 5 |
Вопрос: Оптимизация кода для быстродействия (массивы)
Добавлено: 05.03.08 02:59
Автор вопроса: traford
Ответы
Всего ответов: 63
Номер ответа: 16
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #16
Добавлено: 07.03.08 01:39
Файл почти 500 МБ.
Вот код:
Dim Path = "C:\1.txt"
Dim start = DateTime.Now
Using SR = New StreamReader(Path)
Dim L = SR.ReadLine
Do While (L IsNot Nothing)
Count += 1
Dim Length = L.Length
L = SR.ReadLine
Loop
End Using
Console.WriteLine("Stream Reader: {0}", Now.Subtract(start).ToString)
Console.WriteLine("Count: {0}", Count)
start = Now
Dim Data = File.ReadAllLines(Path)
Console.WriteLine("ReadAllLines: {0}", Now.Subtract(start).ToString)
Console.WriteLine("Length: {0}", Data.Length)
start = Now
Count = 0
For Each L In Data
Count += 1
Dim Length = L.Length
Next
Console.WriteLine("For Each: {0}", Now.Subtract(start).ToString)
Console.WriteLine("Count: {0}", Data.Length)
start = Now
Count = 0
For i = 0 To Data.Length - 1
Count += 1
Dim Length = Data(i).Length
Next
Console.WriteLine("For Next: {0}", Now.Subtract(start).ToString)
Console.WriteLine("Count: {0}", Data.Length)
Console.ReadLine()
Count: 10000001
ReadAllLines: 00:00:24.7500000
Length: 10000001
For Each: 00:00:00.3710000
Count: 10000001
For Next: 00:00:00.2990000
Count: 10000001
Хочу отметить что при выполнении ReadAllLines программа "отъела" в ОЗУ 1.3 с лишним ГБ, и по сути заполнила бОльшую часть моих 2 ГБ ОЗУ.
В принципе просто повезло что памяти хватило - если бы ее не хватило то пошел бы своппинг и на переборе самого массива скорость бы еще упала.
Результаты могу пояснить - считывание данных в массив через ReadAllLines занимает гораздо больше времени, чем обычный перебор строк через StreamReader по той причине что ReadAllLines загружает все стрчоки в массив что сопровождается постоянным выделением новых объемов памяти.
Хотя, если посмотришь рефлектором, сам код чтения данных у меня идентичен тому что используется в ReadAllLines.
Сам процес перебора загруженного массива в ОЗУ происходит очень быстро - как видишь разница между For Next и For Each минимальна (хотя я ожидал что она вообще будет отсутствовать, видимо в For Each вводятся дополнительные проверки), и не сравнима с самим временем загрузки данных.
Для относительно маленького файла (50 мб) время выглядит так:
Count: 1000001
ReadAllLines: 00:00:01.3580000
Length: 1000001
For Each: 00:00:00.0340000
Count: 1000001
For Next: 00:00:00.0310000
Count: 1000001
Т.е. в любом случае перебор через StreamReader будет быстрее.
Другой вопрос - какой собственно анализ текста выполняется - не исключено что в каких-то случаях будет выгодняя грузить в массив и обрабатывать данные уже в массиве.
Но на таком синтетическом тесте - сам видишь какой результат.
Номер ответа: 17
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #17
Добавлено: 07.03.08 01:41
Покажи ВЕСЬ свой код, тогда можно будет о чем-то говорить.
А так ты кидаешь какие-то обрывки с непонятными объяснениями, даже из которых ясно что ты где-то налажал.
StreamReader не может быть медленнее ReadAllLines - тупо потому что ReadAllLines работает с этим классом.
Номер ответа: 18
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #18
Добавлено: 07.03.08 01:54
Да я не говорю что StreamReader медленнее я про Do loop говорил, тот же StreamReader с For...Next быстрей работает, вообщем ща
Номер ответа: 19
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #19
Добавлено: 07.03.08 02:23
Do Loop медленнее чем For Next?
Какой сказочный тупизъм...
Номер ответа: 20
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #20
Добавлено: 07.03.08 02:44
Вот щас гуд, и тот файл обрабатывает где пустая строка была тоже гуд, до этого было как было, в 3 раза дольше, и это не сказочный тупизьм в файле не 1 2 3 4 5 6 7 чего только нету, а смысл темы не что быстрее StreamReader или ReadLines смысл чем быстрее обрабатывать данные, самое быстрое работа с массивом, но он жрёт память, со стримриадером не получиться т.к медленно, в итоге, всё таки юзать массив? с массивом даже секунды не было при обработке строк, а StreamReader'ом 12 секунд
Номер ответа: 21
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #21
Добавлено: 07.03.08 02:50
Я к тому что у меня очень много условий по обработке строк, если построчно считывать + обработка и проверка на все условия скорость ещё ниже упадёт
Номер ответа: 22
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #22
Добавлено: 07.03.08 02:54
Кстати такой вопрос, принудительно вызвать сборщик мусора никак нельзя? скажем после обработки файла перед переходом к другому, тогда он освободит память, читал в статье что можно, даже код был, только статья под первую бету VS и уже синтаксис не подходит, или убрали эту возможность, х.з
Номер ответа: 23
Автор ответа:
BG(Алексей)
Вопросов: 26
Ответов: 295
Профиль | | #23
Добавлено: 07.03.08 05:23
А какие условия проверки строк?
Номер ответа: 24
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #24
Добавлено: 07.03.08 10:11
Много If'ов с разными условиями, также много if "переменная со строкой".Contains("что то там" при некоторых условиях нужны будут данные из других строк, а результат выводиться в String.Builder, и всё это в цикле вообщем быстрее тут походу не чего нельзя сделать, придеться ставить ограничение на входящий файл, одна проблема со сборкой мусора, т.к память слишком долго не освобождается, и при открытии другого файла он заново отъедет память + та что ещё осталась занята от прошлого файла
попробуй выкинуть дотнет и написать на Си++
Наверно стоит задуматься над советом HACKER'a )
Номер ответа: 25
Автор ответа:
mc-black
ICQ: 308-534-060
Вопросов: 20
Ответов: 1860
Web-сайт:
Профиль | | #25
Добавлено: 07.03.08 13:01
Можно много спорить про Stream Reader и другие методы, но вот если писать на API, то я бы тебе настоятельно порекомендовал бы прочесть документацию на тему Memory Maped Files. Так можно существенно уменьшить прожорливость программы до памяти, можно открывать сколь угодно большие файлы. И это даже при наличии не слишком ёмкой памяти на борту.
Номер ответа: 26
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #26
Добавлено: 07.03.08 16:12
mc-black
Спасибо, поищу инфу почитаю, а пока такая лажа у меня получилось оказывается все тормоза из-за прогресс бара...я был в шоке, когда убрал код из цикла и результат получился 2 миллисекунды вместо 20! секунд с прогресс баром, с чем это связанно я до сих пор не могу разобраться, ниже полный код, кидаем на форму прогрессбар ProgressBar1 и кнопку Button1, Код сканит все папки и подпапки и открывает все файлы поочереди, вот код:
Imports System.Text
Imports System.IO
Public Class Form1
Dim arr() As String
Dim SearchLines() As String = {"test"}
Dim start As Date
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
start = DateTime.Now
Dim DI As New DirectoryInfo("C:\TestFolder\"
For Each FI As FileInfo In DI.GetFiles()
arr = File.ReadAllLines(FI.FullName)
ProgressBar1.Maximum = arr.Count
Dim output As New System.Text.StringBuilder
For Each data As String In arr
ProgressBar1.Value += 1
For Each source As String In SearchLines
output.AppendLine(data)
Next
Next
ProgressBar1.Value = 0
Next
MsgBox(Now.Subtract(start).ToString)
End Sub
End Class
Не могу понять что не так с прогресс баром результат: 00:00:13, без него (а именно без ProgressBar1.Value += 1) 00:00:00.2197125, обрабатывалось 2 файла, один весом 1.5мб друго 3.3мб вот х.з что не так, кто что думает?
P.S Все представленные примеры я тестил в новом проекте, после переноса заметил такой глюк
Номер ответа: 27
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #27
Добавлено: 07.03.08 20:01
Проблему с висением файлов в памяти победил банально вызовом сборщика мусора, именно в тот момент когда нужно, вот код вызова
GC.Collect()
Осталась проблема с прогрессбаром, спасибо Steel Brand'у за то что научил работать со StreamReader'ом и объяснил в теории и на практике
Номер ответа: 28
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #28
Добавлено: 07.03.08 22:10
Поставь прогрес бару максимум - 100 и устанавливай текущее значение исходя из количество обработанных строк.
Номер ответа: 29
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #29
Добавлено: 07.03.08 22:11
То есть - устанавливай это значение не на каждой строчке, а грубо говоря, когда кол-во обработанных строк увеличивается на 1%
Номер ответа: 30
Автор ответа:
traford
Вопросов: 1
Ответов: 18
Профиль | | #30
Добавлено: 08.03.08 09:07
Великолепная идея!! Спасибо! я вроде реализовал, возможно криво, если что поправь вот код:
Imports System.Text
Imports System.IO
Public Class Form1
Dim arr() As String
Dim SearchLines() As String = {"test"}
Dim start As Date
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim m As Integer
start = DateTime.Now
Dim DI As New DirectoryInfo("C:\TestFolder\"
For Each FI As FileInfo In DI.GetFiles()
arr = File.ReadAllLines(FI.FullName)
Dim output As New System.Text.StringBuilder
For Each data As String In arr
m += 1
If m = Fix(arr.Count / 100) Then
ProgressBar1.Value += 1
m = 0
End If
For Each source As String In SearchLines
output.AppendLine(data)
Next
Next
ProgressBar1.Value = 0
Next
MsgBox(Now.Subtract(start).ToString)
End Sub
End Class