Reputation: 1539
I have multiple threads that need to write to an Azure queue. To increase throughput, I've created 8 different Azure queues. As a result, I have 8 different connection strings stored in a static string[] array. I'd like to write code that perfectly load balances writing to those queues, by always returning the index of the next queue to write to (and connection string to use), so that queue 0 gets written to the same number of times as queue 1, queue 2, etc. - all in serial succession. I need a way to iterate through indices 0 through 7, in a way that is thread-safe. Is there a more performant and efficient way to write the below code, and how do I make it thread-safe? Thank you very much.
private static int currentQueueIndex = -1; // initial value set to -1 so that index 0 is returned first.
private static int maxIndex = 7;
private static int GetNextQueueIndex()
{
int tempIndex = currentQueueIndex + 1;
if (tempIndex > maxIndex)
{
currentQueueIndex = 0;
return 0;
}
else
{
return tempIndex;
}
}
Upvotes: 2
Views: 101
Reputation: 1539
Thanks to @Cory Nelson, the following is the final solution:
/// <summary>
/// This will return 0 through 7 continuously in a thread-safe manner.
/// </summary>
/// <returns>0, 1, 2, 3, 4, 5, 6, 7, and then back to 0.</returns>
private const int maxIndex = 7; // warning - must be a ([power-of-two number] - 1)
private static int currentQueueIndex = -1;
private static int GetNextQueueIndex()
{
return Interlocked.Increment(ref currentQueueIndex) & (maxIndex);
}
Upvotes: 0
Reputation: 30001
This is a perfect job for the Interlocked
methods, which perform atomic operations on values in memory. This is as fast as you can get when it comes to a globally-visible thread-safe operation.
If you can restrict your queue count to power-of-two numbers, you just mask off the low bits:
private static int GetNextQueueIndex()
{
return Interlocked.Increment(ref currentQueueIndex) & (maxIndex - 1);
}
Or, if you have a non-power-of-two number of queues -- but you asked for perf, so I suggest avoiding a div:
private static int GetNextQueueIndex()
{
int i = Interlocked.Increment(ref currentQueueIndex) & Int32.MaxValue;
return i % maxIndex;
}
Note there is no need to reset currentQueueIndex
back to 0
-- it's perfectly safe to let the storage overflow and mask off just the bits we need.
Upvotes: 3