I have a windows form program that's running 24/7 and about every 15 minutes does some work and then has to make roughly 5000 http calls and I don't need to wait or get any results from the calls just simply hit the http API and move on. I have the http call as a separate sub and what I'm doing now is just spawning a new thread for each call. This works fine on a high CPU machine but when I run on a hosted machine with limited CPU's I get about 1/5 of those threads error with an HTTP timeout.
So my question is how do I process 5000 sub calls independently of my main thread in a way that will process them as quick as possible but not block my application
This is the basic code now:
for i = 1 to 5000
Dim thread As New Thread(
Sub()
sendtoapi(i)
End Sub
)
thread.SetApartmentState(ApartmentState.STA)
Thread.Start()
next i
Private Sub sendtoapi(i as integer)
Dim result As String = ""
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
Using Client As New System.Net.WebClient()
result = Client.DownloadString("https://apiurl/addnumber?num=" & i)
End Using
End Sub
CodePudding user response:
You could limit the number of threads with the Task Parallel Library. Namely, Parallel.For. This would be a great replacement for your For loop.
Parallel.For(1, 5001, Sub(i) sendtoapi(i))
Since you do run from a form timer, then you can continue doing that and make a minor change by using the Async/Await mechanic.
Private WithEvents Timer1 As New System.Windows.Forms.Timer _
With {.Enabled = True, .Interval = 15 * 60 * 1000}
Private Async Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Await Task.Run(Sub() Parallel.For(1, 5001, Sub(i) sendtoapi(i)))
End Sub
This doesn't actually create a new thread, but uses an existing thread from the threadpool. Well, inside the TPL will certainly create new threads :) but Async/Await doesn't by itself.
You could totally take it off the UI with a System.Threading.Timer and not need to worry about blocking the UI. This runs on a threadpool thread, and the TPL will manage whether it utilizes threadpool threads or feels the need to spawn new threads. It will keep your system in control either way.
Private runTimer As New System.Threading.Timer(AddressOf run, Nothing, 0, 15 * 60 * 1000)
Sub run(state As Object)
Parallel.For(1, 5001, Sub(i) sendtoapi(i))
End Sub
