2013-06-07 2 views
2

Я делаю программу, которая должна обрабатывать около 5000 строк как можно быстрее. около 2000 из этих строк должны быть переведены через webrequest на mymemory.translated.net. (См ниже код, JSON часть удаляется, так как здесь не требуется)non blocking webrequests vb.net

Try 

      url = "http://api.mymemory.translated.net/get?q=" & Firstpart & "!&langpair=de|it&[email protected]" 

      request = DirectCast(WebRequest.Create(url), HttpWebRequest) 
      response = DirectCast(request.GetResponse(), HttpWebResponse) 
      myreader = New StreamReader(response.GetResponseStream()) 

      Dim rawresp As String 
      rawresp = myreader.ReadToEnd() 
      Debug.WriteLine("Raw:" & rawresp) 


      Catch ex As Exception 
       MessageBox.Show(ex.ToString) 

      End Try 

сам код работает нормально, проблема в том, что код блокировки и требуется около 1 секунды за строку. Это больше, чем полчаса для всех моих строк. мне нужно будет преобразовать этот код в неблокирующий и сделать несколько вызовов в одно и то же время. Может кто-нибудь, пожалуйста, скажите мне, как я могу это сделать? Я думал о фоновом работнике, но это не ускорит процесс ... он просто выполнит код в другом потоке ...

спасибо!

+0

Is firstpart значение массива или значение из IEnumerable? –

+0

его строка, содержащая текст, который мне нужно перевести .. обычно между 1 и 5 словами – user2452250

+0

Какую версию .NET вы настраиваете? 4,5? –

ответ

2

Проблема в том, что вы не просто сдерживаетесь на максимальное количество одновременных операций. HttpWebRequests дросселируются природой (я считаю, что политика по умолчанию допускает только 2 в любой момент времени), поэтому вам придется переопределить это поведение. См. Код ниже.

Imports System.Diagnostics 
Imports System.IO 
Imports System.Net 
Imports System.Threading 
Imports System.Threading.Tasks 

Public Class Form1 

    ''' <summary> 
    ''' Test entry point. 
    ''' </summary> 
    Private Sub Form1_Load() Handles MyBase.Load 
    ' Generate enough words for us to test thoroughput. 
    Dim words = Enumerable.Range(1, 100) _ 
     .Select(Function(i) "Word" + i.ToString()) _ 
     .ToArray() 

    ' Maximum theoretical number of concurrent requests. 
    Dim maxDegreeOfParallelism = 24 
    Dim sw = Stopwatch.StartNew() 

    ' Capture information regarding current SynchronizationContext 
    ' so that we can perform thread marshalling later on. 
    Dim uiScheduler = TaskScheduler.FromCurrentSynchronizationContext() 
    Dim uiFactory = New TaskFactory(uiScheduler) 

    Dim transformTask = Task.Factory.StartNew(
     Sub() 
     ' Apply the transformation in parallel. 
     ' Parallel.ForEach implements clever load 
     ' balancing, so, since each request won't 
     ' be doing much CPU work, it will spawn 
     ' many parallel streams - likely more than 
     ' the number of CPUs available. 
     Parallel.ForEach(words, New ParallelOptions With {.MaxDegreeOfParallelism = maxDegreeOfParallelism}, 
      Sub(word) 
      ' We are running on a thread pool thread now. 
      ' Be careful not to access any UI until we hit 
      ' uiFactory.StartNew(...) 

      ' Perform transformation. 
      Dim url = "http://api.mymemory.translated.net/get?q=" & word & "!&langpair=de|it&[email protected]" 
      Dim request = DirectCast(WebRequest.Create(url), HttpWebRequest) 

      ' Note that unless you specify this explicitly, 
      ' the framework will use the default and you 
      ' will be limited to 2 parallel requests 
      ' regardless of how many threads you spawn. 
      request.ServicePoint.ConnectionLimit = maxDegreeOfParallelism 

      Using response = DirectCast(request.GetResponse(), HttpWebResponse) 
       Using myreader As New StreamReader(response.GetResponseStream()) 
       Dim rawresp = myreader.ReadToEnd() 

       Debug.WriteLine("Raw:" & rawresp) 

       ' Transform the raw response here. 
       Dim processed = rawresp 

       uiFactory.StartNew(
        Sub() 
        ' This is running on the UI thread, 
        ' so we can access the controls, 
        ' i.e. add the processed result 
        ' to the data grid. 
        Me.Text = processed 
        End Sub, TaskCreationOptions.PreferFairness) 
       End Using 
      End Using 
      End Sub) 
     End Sub) 

    transformTask.ContinueWith(
     Sub(t As Task) 
     ' Always stop the stopwatch. 
     sw.Stop() 

     ' Again, we are back on the UI thread, so we 
     ' could access UI controls if we needed to. 
     If t.Status = TaskStatus.Faulted Then 
      Debug.Print("The transformation errored: {0}", t.Exception) 
     Else 
      Debug.Print("Operation completed in {0} s.", sw.ElapsedMilliseconds/1000) 
     End If 
     End Sub, 
     uiScheduler) 
    End Sub 

End Class 
+0

спасибо! если я это правильно понимаю, этот код будет транслировать 10 строк параллельно, не блокируя .. правильно? – user2452250

+0

Нет. Параллельно будет 10 строк (так что это будет намного быстрее), но он все равно будет блокироваться. Если вы не хотите блокировать, завершите вызов Parallel.ForEach в Задаче и ждите. –

+0

спасибо, попробуем и ответим! – user2452250

2

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

Я не рекомендую стрелять 5000 параллельных нитей/работников, вы должны быть осторожны: Такая загрузка может быть интерпретирована как спам или атака сервера. Не переусердствуйте, возможно, поговорите с transl.net и спросите их о рабочей нагрузке, которую они принимают. Также подумайте о том, что может обрабатывать ваша машина и ваш интернет вверх по течению.

+0

Возможно, вы также захотите использовать [WebRequest.BeginGetResponse()] (http://msdn.microsoft.com/en-us/library/system.net.webrequest.begingetresponse .aspx), чтобы выполнить запрос асинхронно. – Adrian

1

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

For Each InputString As String In myCollectionString 


      Tasks.Task(Of String).Factory.StartNew(Function(inputString) 

        Dim request As HttpWebRequest 
        Dim myreader As StreamReader 
        Dim response As HttpWebResponse 
        Dim rawResp As String = String.Empty 

        Try 

         Dim url As String = "http://api.mymemory.translated.net/get?q=" & inputString & "!&langpair=de|it&[email protected]" 

         request = DirectCast(WebRequest.Create(url), HttpWebRequest) 
         response = DirectCast(request.GetResponse(), HttpWebResponse) 
         myreader = New StreamReader(response.GetResponseStream()) 

         rawResp = myreader.ReadToEnd() 
         Debug.WriteLine("Raw:" & rawResp) 


        Catch ex As Exception 
         MessageBox.Show(ex.ToString) 

        End Try 

        Return rawResp 

       End Function, CancellationToken.None, _ 
       Tasks.TaskCreationOptions.None).ContinueWith _ 
       (Sub(task As Tasks.Task(Of String))                         
       'Dom something with result                               
       Console.WriteLine(task.Result)                              
       End Sub)  

     Next