Rate Limiting in Visual Basic .NET
Here’s the translation of the rate limiting example from Go to Visual Basic .NET:
Rate limiting is an important mechanism for controlling resource utilization and maintaining quality of service. Visual Basic .NET supports rate limiting with threads, timers, and channels (implemented using concurrent collections).
Imports System
Imports System.Threading
Imports System.Collections.Concurrent
Module RateLimiting
Sub Main()
' First we'll look at basic rate limiting. Suppose
' we want to limit our handling of incoming requests.
' We'll serve these requests off a queue of the same name.
Dim requests As New ConcurrentQueue(Of Integer)
For i As Integer = 1 To 5
requests.Enqueue(i)
Next
' This timer will trigger every 200 milliseconds.
' This is the regulator in our rate limiting scheme.
Dim limiter As New Timer(AddressOf ProcessRequest, requests, 0, 200)
' We'll use this to signal when all requests are processed
Dim done As New ManualResetEvent(False)
' By waiting for the timer to trigger before serving each request,
' we limit ourselves to 1 request every 200 milliseconds.
Sub ProcessRequest(state As Object)
Dim queue = DirectCast(state, ConcurrentQueue(Of Integer))
Dim request As Integer
If queue.TryDequeue(request) Then
Console.WriteLine($"request {request} {DateTime.Now}")
Else
limiter.Dispose()
done.Set()
End If
End Sub
' Wait for all requests to be processed
done.WaitOne()
' We may want to allow short bursts of requests in
' our rate limiting scheme while preserving the
' overall rate limit. We can accomplish this by
' using a semaphore. This burstyLimiter will allow
' bursts of up to 3 events.
Dim burstyLimiter As New SemaphoreSlim(3, 3)
' Every 200 milliseconds we'll try to add a new
' permit to burstyLimiter, up to its limit of 3.
Dim burstyTimer As New Timer(
Sub()
burstyLimiter.Release(1)
End Sub,
Nothing,
0,
200)
' Now simulate 5 more incoming requests. The first
' 3 of these will benefit from the burst capability
' of burstyLimiter.
Dim burstyRequests As New ConcurrentQueue(Of Integer)
For i As Integer = 1 To 5
burstyRequests.Enqueue(i)
Next
Dim burstyDone As New ManualResetEvent(False)
Sub ProcessBurstyRequest(state As Object)
Dim queue = DirectCast(state, ConcurrentQueue(Of Integer))
Dim request As Integer
If queue.TryDequeue(request) Then
burstyLimiter.Wait()
Console.WriteLine($"request {request} {DateTime.Now}")
ThreadPool.QueueUserWorkItem(AddressOf ProcessBurstyRequest, queue)
Else
burstyTimer.Dispose()
burstyDone.Set()
End If
End Sub
ThreadPool.QueueUserWorkItem(AddressOf ProcessBurstyRequest, burstyRequests)
' Wait for all bursty requests to be processed
burstyDone.WaitOne()
End Sub
End Module
Running our program, we would see the first batch of requests handled once every ~200 milliseconds as desired.
For the second batch of requests, we would serve the first 3 immediately because of the burstable rate limiting, then serve the remaining 2 with ~200ms delays each.
In this Visual Basic .NET implementation:
- We use
ConcurrentQueue(Of Integer)
instead of channels to store requests. Timer
is used to implement the rate limiting logic.SemaphoreSlim
is used to implement the bursty limiter.ThreadPool.QueueUserWorkItem
is used to process requests asynchronously.ManualResetEvent
is used to signal when all requests have been processed.
This implementation preserves the core concepts of rate limiting and bursty rate limiting from the original example, adapted to the idioms and available constructs in Visual Basic .NET.