【问题标题】:Downloading webpage contents in parallel using async使用异步并行下载网页内容
【发布时间】:2016-08-23 14:32:37
【问题描述】:

我正在使用来自 Microsoft 的 example,它使用 AsyncTasks 下载多个 URL 的数据。

我的要求是在 1 分钟内完成 200 个链接的下载,以便在第 2 分钟再次开始下载同一组 200 个 URL。我知道这在很大程度上取决于网络速度,并且在较小程度上取决于 CPU 功率,因为​​这不是 IO 绑定进程。

假设网络和 CPU 将支持此操作并且不会成为瓶颈,我实际上在任务一段时间后看到超时和取消异常。

因此,在同一个示例中,我可以将其更改为长时间运行的任务,以使任务不会超时吗?我知道TaskCreationOptions 枚举的使用和LongRunning 的使用。然而,问题是: 1)如何在创建以下示例中的任务和提供的链接时提供此参数? 2)LongRunning的定义是什么?这是否意味着每个任务将不再超时? 3)我可以通过其他方式明确设置无限超时吗?

基本上,我的要求是,如果特定 URL 的下载过程完成,它将再次触发相同 URL 的下载 - 这意味着将一遍又一遍地下载相同的 URL,因此该任务永远不会完成(MSDN 示例中的 URL 不是我要触发的 URL,还有其他 URL,其内容每分钟都会更改,因此我需要至少每分钟持续下载一次 URL。

也将上述示例链接中的代码粘贴到此处:

Dim cts As CancellationTokenSource
Dim countProcessed As Integer

Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)

    ' Instantiate the CancellationTokenSource.
    cts = New CancellationTokenSource()

    resultsTextBox.Clear()

    Try
        Await AccessTheWebAsync(cts.Token)
        resultsTextBox.Text &= vbCrLf & "Downloads complete."

    Catch ex As OperationCanceledException
        resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf

    Catch ex As Exception
        resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf
    End Try

    ' Set the CancellationTokenSource to Nothing when the download is complete.
    cts = Nothing
End Sub

Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
End Sub

Async Function AccessTheWebAsync(ct As CancellationToken) As Task

    Dim client As HttpClient = New HttpClient()

    ' Call SetUpURLList to make a list of web addresses.
    Dim urlList As List(Of String) = SetUpURLList()

    ' ***Create a query that, when executed, returns a collection of tasks.
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url, client, ct)

    ' ***Use ToList to execute the query and start the download tasks. 
    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()

    Await Task.WhenAll(downloadTasks)
    'Ideally, this line should never be reached
    Console.WriteLine("Done")

End Function

Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)
    Console.WriteLine("URL=" & url)
    ' GetAsync returns a Task(Of HttpResponseMessage). 
    Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

    ' Retrieve the web site contents from the HttpResponseMessage.
    Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
    Interlocked.Increment(countProcessed)
    Console.WriteLine(countProcessed)
    Return urlContents.Length
End Function

Private Function SetUpURLList() As List(Of String)

    Dim urls = New List(Of String) From
        {
            "http://msdn.microsoft.com",
            "http://msdn.microsoft.com/en-us/library/hh290138.aspx",
            "http://msdn.microsoft.com/en-us/library/hh290140.aspx",
            "http://msdn.microsoft.com/en-us/library/dd470362.aspx",
            "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
            "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
            "http://msdn.microsoft.com/en-us/library/ff730837.aspx",
            "http://msdn.microsoft.com/en-us/library/hh290138.aspx",
            "http://msdn.microsoft.com/en-us/library/hh290140.aspx"
    'For space constraint I am not including the 200 URLs, but pls assume the above list contains 200 URLs
    }

    Return urls
End Function

【问题讨论】:

    标签: .net vb.net parallel-processing async-await task-parallel-library


    【解决方案1】:

    因此,在同一个示例中,问题是,我能否将其更改为长时间运行的任务,以使任务不会超时?

    任务本身不会超时。您可能看到的是 HTTP 请求超时。长时间运行的任务没有任何不同的超时语义。

    我知道 TaskCreationOptions 枚举的用法和 LongRunning。

    您还应该知道,它们几乎不应该被使用。


    您可能会遇到超时,因为您的所有请求都访问同一个网站。尝试将ServicePointManager.DefaultConnectionLimit 设置为int.MaxValue,也可能增加HttpClient.Timeout

    【讨论】:

    • 谢谢斯蒂芬。我认为ServicePointManager.DefaultConnectionLimit 成功了。当然,我也设置了HttpClient.Timeout,但没有注意到有和没有它的任何区别。但我现在得到随机错误读取流”。我的猜测是因为在请求和读取之间与流的连接关闭。在这种情况下,我的要求是等待,比如说 20 秒,然后重试URL。但是,HttpClient 对象将超时。任何建议我应该如何构造代码以便我也可以重试而不会超时?
    • 你可以await Task.Delay然后重新调用Get*。我建议使用 Polly 之类的库进行生产质量重试。
    猜你喜欢
    • 1970-01-01
    • 2018-01-15
    • 2015-03-23
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    相关资源
    最近更新 更多