【问题标题】:Multi-threading with WebRequest and StreamWriter in VB.NETVB.NET 中使用 WebRequest 和 StreamWriter 的多线程
【发布时间】:2017-01-15 15:52:49
【问题描述】:

我需要让它在线程中工作,例如,thread1用'order_id=1'调用url,thread2用'order_id=2'调用url等等,然后将结果写入文件.

代码如下:

Public Sub download()
    Dim address As String = "http://www.example.com/sales.php&order_id="
    Dim FILE_NAME As String = "D:\Folder\Licenses.txt"
    Dim index As Integer = 0

    Do While index <= 100
            If index > 100 Then
                Exit Do
            End If
        Try
            Dim request As WebRequest = WebRequest.Create(address & index.ToString)
            Dim response As WebResponse = request.GetResponse()                
            If CType(response, HttpWebResponse).StatusDescription = "OK" Then
                Dim dataStream As Stream = response.GetResponseStream()
                Dim reader As New StreamReader(dataStream)
                Dim responseFromServer As String = reader.ReadToEnd()
                If Not File.Exists(FILE_NAME) Then
                    Using sw As StreamWriter = File.CreateText(FILE_NAME)
                        sw.WriteLine(responseFromServer)
                        index += 1
                    End Using
                ElseIf File.Exists(FILE_NAME) Then
                    Using sw As StreamWriter = File.AppendText(FILE_NAME)
                        sw.WriteLine(responseFromServer)
                        index += 1
                    End Using
                End If
            End If
        Catch ex As Exception
        End Try
        Loop
End Sub

【问题讨论】:

  • 你需要按id排序的输出文件吗?
  • 并非如此。它应该保存在一个文件中。
  • 请永远不要写Catch ex As Exception - 特别是使用空的catch块。否则,您似乎在尝试编写错误代码。
  • 另外,responsedataStreamreader 都需要处理。

标签: vb.net multithreading streamwriter


【解决方案1】:

一个非常简单的方法是使用Parallel.For()。您只需要确保不会同时将不同的内容写入输出文件。这是通过Monitor 解决的,它确保临界区中只有一个线程。省略异常处理:

Dim address As String = "http://www.example.com/sales.php&order_id="
Dim FILE_NAME As String = "D:\Folder\Licenses.txt"

Using fstream As New StreamWriter(FILE_NAME)
    Parallel.For(0, 100, Sub(i As Integer)
                           Dim client As New WebClient
                           Dim content = client.DownloadString(address + i.ToString())
                           Monitor.Enter(fstream)
                           fstream.WriteLine(content)
                           Monitor.Exit(fstream)
                       End Sub)
End Using

可以通过将 Web 客户端创建为线程本地对象来改进此示例。这将避免为每次迭代创建新客户端。

【讨论】:

    【解决方案2】:

    我想看看微软的响应式框架(NuGet "System.Reactive" 或 "Rx-Main" 来获取这些信息)。

    那么你可以这样做:

    Public Sub download()
    
        Dim address As String = "http://www.example.com/sales.php&order_id="
        Dim FILE_NAME As String = "D:\Folder\Licenses.txt"
    
        Dim download As Func(Of Integer, String) = _
            Function(n)
                Using wc As New WebClient()
                    Return wc.DownloadString(New Uri(address & n.ToString()))
                End Using
            End Function
    
        Dim query = _
            From index In Observable.Range(0, 101) _
            From result In Observable.Start(Function () download(index))
            Select New With {.Index = index, .Result = result}
    
        Dim results = _
            query _
                .ToArray() _
                .Select(Function(xs) xs _
                    .OrderBy(Function(x) x.Index) _
                    .Select(Function(x) x.Result) _
                    .ToArray())
    
        results.Do(Sub(lines) File.WriteAllLines(FILE_NAME, lines)).Wait()
    
    End Sub
    

    这将异步查询每个 URL,然后在完成后执行单个文件写入。

    【讨论】:

      猜你喜欢
      • 2010-12-01
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多