全部使用httpclient时取消不返回过去 [英] Cancellation not returning past whenall using httpclient

查看:115
本文介绍了全部使用httpclient时取消不返回过去的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此处是 httpclient.GetStringAsync阻止

问题是取消操作何时完成,尽管任务已取消,但我希望等待Task.WhenAll(tasks)返回并最终打印 中的内容,但不是。我可以在按下取消时看到任务取消,并且连接也减少到0,但是最终猜测 WhenAll 仍然认为某些任务正在执行。

The question is when cancel is done, though the tasks are cancelled, I am expecting Await Task.WhenAll(tasks) to return and print whats in finally, but its not. I can see task cancellations when pressing cancel and I also see the connections reduce to 0, but the finally guessing WhenAll still thinks some tasks are being executed.

这是代码:

Private concurrencySemaphore As New SemaphoreSlim(10)
Private cts As CancellationTokenSource
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Try
        cts = New CancellationTokenSource
        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
            cts.Token.ThrowIfCancellationRequested()
            tasks.Add(GetUrl(url, cts.Token))
        Next
        Await Task.WhenAll(tasks)
    Catch tx As TaskCanceledException
        Console.WriteLine("Task was cancelled")
    Catch ox As OperationCanceledException
        Console.WriteLine("Operation was cancelled")
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    Finally
        Console.WriteLine("Done")
    End Try
End Sub
Async Function GetUrl(url As String, ByVal ct As CancellationToken) As Task
    Try
        ct.ThrowIfCancellationRequested()
        Await concurrencySemaphore.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}
        ct.ThrowIfCancellationRequested()
        Dim responseMessage As HttpResponseMessage = Await httpClient.GetAsync(url, ct).ConfigureAwait(False)
        Dim response As String = Await responseMessage.Content.ReadAsStringAsync()
        For Each cook As Cookie In cookies.GetCookies(baseAddress)
            Console.WriteLine(cook.Name & "=" & cook.Value)
        Next
        httpClient.Dispose()
        concurrencySemaphore.Release()
    Catch tx As TaskCanceledException
        Console.WriteLine("Task Cancelled Exception")
    Catch ox As OperationCanceledException
        Console.WriteLine("Operation Cancelled Exception")
    End Try
End Function

Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
End Sub

更新
根据@ I3arnon建议更改了问题。

UPDATE: Have changed the question based on @I3arnon suggestion.

但是下面的代码现在有3个问题:

But 3 problems in the code below now:

 Dim downLoader As TransformBlock(Of String, Task(Of String))
 Dim cts As CancellationTokenSource
 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    cts = New CancellationTokenSource
    Dim urls As List(Of String) = SetUpURLList()
    Dim tasks As List(Of Task) = New List(Of Task)()
    downLoader.Post(urls(0))
    downLoader.Post(urls(1))
    'For Each url In urls
    '    tasks.Add(downLoader.Post(url))
    'Next
End Sub

Private Sub TPL_Load(sender As Object, e As EventArgs) Handles Me.Load
    downLoader = New TransformBlock(Of String, Task(Of String))(
    Async Function(url) As Task(Of String)
        Console.WriteLine("Downloading URL:{0}", url)
        Dim httpClient = New HttpClient()
        Using responseMessage As HttpResponseMessage = Await httpClient.GetAsync(url).ConfigureAwait(False)
            Dim response As String = Await responseMessage.Content.ReadAsStringAsync()
            Return response
            Console.WriteLine("Downloaded, URL:{0}, length:{1}", url, response.Length)
        End Using
    End Function, New ExecutionDataflowBlockOptions With {.MaxDegreeOfParallelism = 4, .CancellationToken = cts.Token})
End Sub




  1. 代码无法编译,因为我不确定 TransformBlock的位置签名和正文。由于未创建对象,将其放入 load 时会导致空异常。

  1. Code doesnt compile as I am not sure where to the TransformBlock signature and body. Putting it inside load is resulting in a null exception when it is being called since the object is not created.

我们现在如何并行触发多个URL

How to we now fire the multiple URLs in parallel

既然 CancellationToken 传递给扩展名,但不传递给完成任务的内部方法。

How do we ensure cancellations, now that the CancellationToken is passed to the extension but not the inner method that does the job.


推荐答案

问题是在发生异常(或您的情况下取消)时,您不会释放信号量。这意味着 Task.WhenAll 正在等待永远无法完成的任务,因为它们正在等待该信号量。

The problem is that you don't release the semaphore when there's an exception (or cancellation in your case). That means Task.WhenAll is waiting for tasks that will never complete since they are waiting for that semaphore.

将信号的释放移动到 Finally 块,以确保它从未被跳过:

Move the semaphore's release to a Finally block to make sure it's never skipped:

Async Function GetUrl(url As String, ByVal ct As CancellationToken) As Task
    Try
        ct.ThrowIfCancellationRequested()
        Await concurrencySemaphore.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}
        ct.ThrowIfCancellationRequested()
        Dim responseMessage As HttpResponseMessage = Await httpClient.GetAsync(url, ct).ConfigureAwait(False)
        Dim response As String = Await responseMessage.Content.ReadAsStringAsync()
        For Each cook As Cookie In cookies.GetCookies(baseAddress)
            Console.WriteLine(cook.Name & "=" & cook.Value)
        Next
        httpClient.Dispose()
    Catch tx As TaskCanceledException
        Console.WriteLine("Task Cancelled Exception")
    Catch ox As OperationCanceledException
        Console.WriteLine("Operation Cancelled Exception")
    Finally
        concurrencySemaphore.Release()
    End Try
End Function

这篇关于全部使用httpclient时取消不返回过去的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆