Этот код занимает около 30 минут и сильно загружен, в чем проблема

Do
  strLine = objReader.ReadLine()
  If strLine Is Nothing Then
    Exit Do
  End If
  'check valid proxy
  m = Regex.Match(strLine.Trim, strProxyParttern)
  strMatch = m.Value.Trim
  If String.IsNullOrEmpty(strMatch) = True OrElse _
    strMatch.Contains("..") = True Then
    Continue Do
  End If
  ' create proxy
  With tmpProxy
    .IP = strMatch.Substring(0, strMatch.IndexOf(":"))
    .Port = CInt(strMatch.Substring(strMatch.IndexOf(":") + 1))
    .Status = "new"
  End With
  ' check 
  If lstProxys.Contains(tmpProxy) = True Then
    Continue Do
  End If
  lstProxys.Add(tmpProxy)
  Debug.Print(lstProxys.Count.ToString)
Loop Until strLine Is Nothing
If lstProxys.Count < 1 Then
  Exit Sub
End If

Медлительность от сравнения, чтения файла или регулярного выражения?

ИЗМЕНИТЬ

Профилирование кода, как это

 Dim myTimer As New System.Diagnostics.Stopwatch()
        Dim t1 As Integer = 0
        Dim t2 As Integer = 0
        Dim t3 As Integer = 0
        'read the file line by line, collecting valid proxy
        Do
            'Read a line fromn the file
            myTimer.Reset()
            myTimer.Start()
            strLine = objReader.ReadLine()
            If strLine Is Nothing Then
                Exit Do
            End If
            myTimer.Stop()
            t1 = myTimer.Elapsed.Milliseconds
            'check valid proxy
            myTimer.Reset()
            myTimer.Start()
            m = Regex.Match(strLine.Trim, strProxyParttern)
            strMatch = m.Value.Trim
            If String.IsNullOrEmpty(strMatch) = True OrElse _
                strMatch.Contains("..") = True Then
                Continue Do
            End If
            myTimer.Stop()
            t2 = myTimer.Elapsed.Milliseconds
            ' create proxy
            myTimer.Reset()
            myTimer.Start()
            tmpProxy.IP = strMatch.Substring(0, strMatch.IndexOf(":"))
            tmpProxy.Port = CInt(strMatch.Substring(strMatch.IndexOf(":") + 1))
            tmpProxy.Status = "new"

            ' check 
            If lstProxys.Contains(tmpProxy) = True Then
                Continue Do
            End If
            lstProxys.Add(tmpProxy)
            myTimer.Stop()
            t2 = myTimer.Elapsed.Milliseconds
            Debug.Print(String.Format("Read={0}, Match={1}, Add={2}", t1, t2, t3))
        Loop Until strLine Is Nothing

Дал эти результаты

Read=0, Match=0, Add=1
Read=0, Match=0, Add=1
Read=0, Match=0, Add=2
...
Read=0, Match=0, Add=9
Read=0, Match=0, Add=9
Read=0, Match=0, Add=10
...
...
Read=0, Match=0, Add=39
Read=0, Match=0, Add=39
Read=0, Match=0, Add=40
etc

Похоже, код в порядке, кроме добавления в список

0
Smith 26 Авг 2011 в 23:51

3 ответа

Лучший ответ

Проблема скорости заключается в том, что вы используете список (структуры). Метод List.Contains - это линейный поиск (он просматривает каждый элемент списка, чтобы увидеть, соответствует ли он), поэтому он занимает все больше времени, чем больше уникальных элементов вы добавляете в список.

Поскольку вы имеете дело с большим количеством элементов, замените lstProxys на HashSet (Of T). Вы должны увидеть огромный прирост производительности. Все, что вам нужно сделать, это изменить определение lstProxys:

Dim lstProxys as New HashSet(Of structure)
2
briddums 26 Авг 2011 в 23:42

Дисковый ввод-вывод обычно является ограничивающим фактором для чего-то вроде этого. В зависимости от скорости диска вы можете ожидать пропускную способность около 5-20 мегабайт в секунду.

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

Поскольку в списке прокси никогда не будет более одного элемента, такое сравнение не может быть проблемой. Вы не создаете новый прокси-объект, а используете его повторно, что означает, что вы изменяете свойство объекта, который вы уже добавили в список. Поскольку вы сравниваете объект с самим собой, список всегда будет содержать объект после первой итерации и никогда не будет добавлен во второй раз.

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

1
Guffa 26 Авг 2011 в 20:11

медлительность от сравнения, чтения файла или регулярного выражения?

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

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

'Test 1 Just IO

Do
  strLine = objReader.ReadLine()

Loop Until strLine Is Nothing
If lstProxys.Count < 1 Then
  Exit Sub
End If

'Test 2 IO + Regex

Do
  strLine = objReader.ReadLine()
  If strLine Is Nothing Then
    Exit Do
  End If
  'check valid proxy
  m = Regex.Match(strLine.Trim, strProxyParttern)
  strMatch = m.Value.Trim
  If String.IsNullOrEmpty(strMatch) = True OrElse _
    strMatch.Contains("..") = True Then
    Continue Do
  End If

Loop Until strLine Is Nothing
If lstProxys.Count < 1 Then
  Exit Sub
End If

'Test 3 IO + regex and Compare
Do
  strLine = objReader.ReadLine()
  If strLine Is Nothing Then
    Exit Do
  End If
  'check valid proxy
  m = Regex.Match(strLine.Trim, strProxyParttern)
  strMatch = m.Value.Trim
  If String.IsNullOrEmpty(strMatch) = True OrElse _
    strMatch.Contains("..") = True Then
    Continue Do
  End If
  ' create proxy
  With tmpProxy
    .IP = strMatch.Substring(0, strMatch.IndexOf(":"))
    .Port = CInt(strMatch.Substring(strMatch.IndexOf(":") + 1))
    .Status = "new"
  End With
  ' check 
  If lstProxys.Contains(tmpProxy) = True Then
    Continue Do
  End If
  lstProxys.Add(tmpProxy)
  Debug.Print(lstProxys.Count.ToString)
Loop Until strLine Is Nothing
If lstProxys.Count < 1 Then
  Exit Sub
End If
1
Conrad Frix 26 Авг 2011 в 20:11