You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET Framework 4.0中限制最多20个线程发送Web请求?

.NET Framework 4.0下实现最多20线程批量发送Web请求

方案一:使用Parallel.ForEach(快速改造首选)

Parallel.ForEach是.NET 4.0自带的并行循环工具,能直接控制最大并发数,适合新手快速修改现有代码。

修改后的SendToServer函数

Friend Function SendToServer(ByVal Datos As List(Of String), ByVal User As String, ByVal Password As String) As Integer
    Dim ErrorCount As Integer = 0

    BGW_Report("Sending " & Datos.Count.ToString & " event(s).", Color.Purple)

    Try
        ' 配置并行循环,限制最大并发数为20
        Dim parallelOpts As New ParallelOptions()
        parallelOpts.MaxDegreeOfParallelism = 20

        Parallel.ForEach(Datos, parallelOpts, Sub(Eventox)
                                                     Dim data = Encoding.UTF8.GetBytes(Eventox)
                                                     Dim xUri As New Uri(My.Settings.WebAddress)
                                                     Dim result_post As String = ""

                                                     Try
                                                         result_post = SendRequest(xUri, data, "application/json", "POST")

                                                         ' 原子性更新错误计数,避免多线程冲突
                                                         If Not result_post.Contains("Process OK") Then
                                                             Interlocked.Increment(ErrorCount)
                                                         End If

                                                         ' 若BGW_Report需更新UI,必须切换到UI线程执行
                                                         Me.Invoke(Sub()
                                                                       BGW_Report($"Sent event: {Eventox}", Color.Green)
                                                                   End Sub)
                                                     Catch ex As Exception
                                                         Interlocked.Increment(ErrorCount)
                                                         ' 线程安全地报告错误
                                                         Me.Invoke(Sub()
                                                                       BGW_Report($"Failed to send event: {Eventox}", Color.Red)
                                                                       BGW_Report(ex.Message, Color.Red)
                                                                       BGW_Report(ex.StackTrace, Color.OrangeRed)
                                                                   End Sub)
                                                     End Try
                                                 End Sub)

    Catch ex As Exception
        BGW_Report($"Parallel processing failed: {ex.Message}", Color.Red)
        BGW_Report(ex.StackTrace, Color.OrangeRed)
        ErrorCount = -1
    End Try

    Return ErrorCount
End Function

核心要点

  • MaxDegreeOfParallelism:直接设置为20,确保同时运行的任务不超过20个。
  • Interlocked.Increment:保证多线程环境下错误计数的准确性,避免并发修改导致的数值异常。
  • Control.Invoke:如果BGW_Report是更新UI的方法,必须通过Invoke切换到UI线程,否则会触发跨线程操作异常。若你的BGW_Report内部已经处理了线程切换(比如基于BackgroundWorker的ReportProgress),可省略此步骤。

方案二:使用SemaphoreSlim控制并发(更灵活)

如果需要更精细地管控并发流程,比如手动控制任务启动顺序,可采用SemaphoreSlim实现信号量限流。

修改后的SendToServer函数

Friend Function SendToServer(ByVal Datos As List(Of String), ByVal User As String, ByVal Password As String) As Integer
    Dim ErrorCount As Integer = 0
    ' 创建信号量,允许最多20个并发任务
    Dim semaphore As New SemaphoreSlim(20)
    Dim taskList As New List(Of Task)()

    BGW_Report("Sending " & Datos.Count.ToString & " event(s).", Color.Purple)

    Try
        For Each Eventox As String In Datos
            ' 获取信号量,超过20个任务时自动阻塞
            semaphore.Wait()

            ' 启动异步任务处理单个请求
            Dim task = Task.Factory.StartNew(Sub(state)
                                                Dim eventData As String = CStr(state)
                                                Dim data = Encoding.UTF8.GetBytes(eventData)
                                                Dim xUri As New Uri(My.Settings.WebAddress)
                                                Dim result_post As String = ""

                                                Try
                                                    result_post = SendRequest(xUri, data, "application/json", "POST")

                                                    If Not result_post.Contains("Process OK") Then
                                                        Interlocked.Increment(ErrorCount)
                                                    End If

                                                    Me.Invoke(Sub()
                                                                  BGW_Report($"Sent event: {eventData}", Color.Green)
                                                              End Sub)
                                                Catch ex As Exception
                                                    Interlocked.Increment(ErrorCount)
                                                    Me.Invoke(Sub()
                                                                  BGW_Report($"Failed to send event: {eventData}", Color.Red)
                                                                  BGW_Report(ex.Message, Color.Red)
                                                                  BGW_Report(ex.StackTrace, Color.OrangeRed)
                                                              End Sub)
                                                Finally
                                                    ' 任务完成后释放信号量,允许新任务进入
                                                    semaphore.Release()
                                                End Try
                                            End Sub, Eventox)

            taskList.Add(task)
        Next

        ' 等待所有任务执行完毕
        Task.WaitAll(taskList.ToArray())

    Catch ex As Exception
        BGW_Report($"Concurrent processing failed: {ex.Message}", Color.Red)
        BGW_Report(ex.StackTrace, Color.OrangeRed)
        ErrorCount = -1
    Finally
        ' 释放信号量资源
        semaphore.Dispose()
    End Try

    Return ErrorCount
End Function

核心要点

  • SemaphoreSlim(20):设定同时允许执行的任务上限为20。
  • Wait/Release:每个任务启动前获取信号量,完成后释放,确保并发数始终不超过设定值。Release放在Finally块中,避免任务异常导致信号量无法释放。
  • Task.Factory.StartNew:.NET 4.0中创建异步任务的标准方式,比手动创建Thread更高效、易管理。

通用注意事项

  1. 线程安全:所有共享变量(如ErrorCount)必须用线程安全的方式更新,Interlocked类是最简便的选择。
  2. UI线程约束:任何修改UI的操作必须在UI线程执行,避免跨线程异常。
  3. 异常隔离:每个子任务内部单独捕获异常,防止单个请求失败导致整个批量任务中断。
  4. SendRequest兼容性:原SendRequest函数可直接复用,因为每个请求都是独立的WebRequest实例,线程安全。

内容的提问来源于stack exchange,提问作者E_Blue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:13:24