For Loop Paradox
So first of all what is the for loop paradox?
It happens when you use i
value of a for loop inside an async Task
. What will happen is that your task will run only using the last value of i
. Maybe if your for loop is very big some of your Tasks might get also some intermediate values.
But let's see some code to demonstrate this behavior:
class Program
{
static async Task Main(string[] args)
{
var tasks = new List<Task>();
for (var i = 0; i <= 9; i++)
{
tasks.Add(Task.Run(() =>
{
Console.WriteLine(i);
}));
}
await Task.WhenAll(tasks.ToArray());
}
}
The expected result would be to print on the console all the values from 0 to 9 in a random order since these are Tasks and ordering is not guaranteed.
But let's see what we actually get:
Hmmm... something is wrong we are actually printing only the number 10 which is not expected at all...
Why is this happening?
This is a common behavior with closures, what happen is that this piece of code:
tasks.Add(Task.Run(() =>
{
Console.WriteLine(i);
}));
is using the value that i
has at the time of the execution.
Closures close over variables, not over values.
Ok, but how to work around this behavior?
The fix is pretty simple, just assign the i
value to a new variable.
class Program
{
static async Task Main(string[] args)
{
var tasks = new List<Task>();
for (var i = 0; i <= 9; i++)
{
// work around for closure behavior
var j = i;
tasks.Add(Task.Run(() =>
{
// use the new j variable here
Console.WriteLine(j);
}));
}
await Task.WhenAll(tasks.ToArray());
}
}
Now every time we iterate over the for loop, we create a new variable j. Each closure is closed over a different j variable, which is assigned only once and keeps the correct current value of i
variable at each iteration.
Now in our console we get the expected results!
History Lesson Incoming!
This behavior was also happening when using foreach
loop but the C# Team did a breaking change when they released the C# 5 and "fix" this behavior.
But for the for loop
they decided to keep it as it is.
More resources
You can read more about closures in C# and how to use them to your advantage on the article of one and only Jon Skeet The Beauty of Closures
I hope that by reading this article I'll save you some debug time!
This post was written with love ❤️
Top comments (0)