2014-12-31 4 views
1

Я должен делать что-то неправильно, так как этот код блокируется и работает синхронно, несмотря на вызов метода asyncGetStringAsync. Любая помощь действительно поможет мне понять причины:httpclient.GetStringAsync blocking

Private Async Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click 
    Dim urls As List(Of String) = SetUpURLList() 
    Dim baseAddress = New Uri("http://www.amazon.com") 
    ServicePointManager.DefaultConnectionLimit = 10 
    Dim requestNumber As Integer = 0 
    For Each url In urls 
     requestNumber += 1 
     Console.WriteLine("Request #:{0}", requestNumber) 
     Dim cookies As New CookieContainer() 
     Dim handler As New HttpClientHandler With {.CookieContainer = cookies, _ 
                .UseCookies = True} 
     Dim httpClient = New HttpClient(handler) With {.BaseAddress = baseAddress} 
     Dim response As String = Await HttpClient.GetStringAsync(url).ConfigureAwait(False) 
     For Each cook As Cookie In cookies.GetCookies(baseAddress) 
      Console.WriteLine(cook.Name & "=" & cook.Value) 
     Next 
     httpClient.Dispose() 
    Next 

    Console.WriteLine("Done") 
End Sub 
+1

Вы уверены, что блокируете вызов 'GetStringAsync'? –

+0

Когда я даю точку останова в Dim-ответе As String = Await HttpClient.GetStringAsync (url) .ConfigureAwait (False), тогда код ломается в первый раз, а затем при воспроизведении он ожидал, что он снова сломается для второго URL GetAsyn и таким образом ломается до первого или любого вызова asyn. То не происходит, оно ломается в вышеуказанной строке и при выполнении, оно завершает указанную выше строку, а затем переходит на следующую строку и после завершения всего цикла переходит во второй URL-адрес и снова разбивается на строку. – Kallol

+0

Кроме того, видели только один порт TCP, который создается, закрывается, а затем снова создается и так далее, когда цикл перемещается. – Kallol

ответ

1

Ваш код не блокирует, он просто последователен. Вы запускаете каждую операцию Async и асинхронно ожидаете ее завершения с Await перед началом следующего.

Если вы хотите одновременно стрелять все эти операции сначала создать задачу для каждого url и затем Await всех этих задач одновременно, используя Task.WhenAll:

Dim semaphore As New SemaphoreSlim(10) 
Async Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click 
    Dim urls As List(Of String) = SetUpURLList() 
    ServicePointManager.DefaultConnectionLimit = 10 
    Dim tasks As List(Of Task) = new List(Of Task)() 
    For Each url In urls 
     tasks.Add(GetUrlAsync(url)) 
    Next 
    Await Task.WhenAll(tasks) 
    Console.WriteLine("Done") 
End Sub 

Async Function GetUrlAsync(url As String) As Task 
    Await semaphore.WaitAsync() 
    Dim baseAddress = New Uri("http://www.amazon.com") 
    Dim cookies As New CookieContainer() 
    Dim handler As New HttpClientHandler With {.CookieContainer = cookies, _ 
               .UseCookies = True} 
    Dim httpClient = New HttpClient(handler) With {.BaseAddress = baseAddress} 
    Dim response As String = Await HttpClient.GetStringAsync(url).ConfigureAwait(False) 
    For Each cook As Cookie In cookies.GetCookies(baseAddress) 
     Console.WriteLine(cook.Name & "=" & cook.Value) 
    Next 
    httpClient.Dispose() 
    semaphore.Release() 
End Sub 

* Я надеюсь, что этот код имеет смысл, так как я m не очень хорошо знаком с VB.Net.

+0

Thx l3arnon. Это асинхронно, и теперь открывается несколько портов. Я думал, что GetStringAsync также возвращает задачу и, следовательно, не создает явную задачу. Похоже, я неправильно понял эту концепцию.Кстати, я заметил, что более 10 подключений открываются сразу. DefaultMaxConnections должен был дросселировать в 10. Его не работает - какие-то идеи? Если я напишу свой пользовательский дроссель с помощью Semaphoreslim, смогу ли я использовать WhenAll? – Kallol

+0

@ Каллоль Да. «СемафорСлим» был бы лучше для дросселирования. Используйте его внутри 'GetUrl', и вы все равно можете использовать' Task.WhenAll' – i3arnon

+0

@Kallol 'GetStringAsync' возвращает« Задачу ». разница здесь в том, когда вы используете 'Await'. Вы использовали 'Await' для каждой отдельной' Задачи', в то время как это использует 'Await' один раз для всех объединенных задач. – i3arnon

0

Вот полный рабочий код сейчас - thx to @ l3arnon для всех огней и дожидайтесь завершения.

Dim concurrencySemaphore As New SemaphoreSlim(10) 
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Dim urls As List(Of String) = SetUpURLList() 
    ServicePointManager.DefaultConnectionLimit = 10 'Not working strangely 
    Dim tasks As List(Of Task) = New List(Of Task)() 
    For Each url In urls 
     tasks.Add(GetUrl(url)) 
    Next 
    Await Task.WhenAll(tasks) 
    Console.WriteLine("Done") 
End Sub 
Async Function GetUrl(url As String) As Task 
    concurrencySemaphore.Wait() 
    Dim baseAddress = New Uri("http://www.amazon.com") 
    Dim cookies As New CookieContainer() 
    Dim handler As New HttpClientHandler With {.CookieContainer = cookies, _ 
               .UseCookies = True} 
    Dim httpClient = New HttpClient(handler) With {.BaseAddress = baseAddress} 
    Dim response As String = Await httpClient.GetStringAsync(url).ConfigureAwait(False) 
    For Each cook As Cookie In cookies.GetCookies(baseAddress) 
     Console.WriteLine(cook.Name & "=" & cook.Value) 
    Next 
    httpClient.Dispose() 
    concurrencySemaphore.Release() 
End Function