So I have 3 nested for loops with the inner two doing little work. I want to convert the outer-most loop into a parallel one.
My question is:
If I have a variable inside the loop, something that is used as a temp value holder and takes a new value each loop. Do I need to worry about that variable when the parallelism begins ?
I mean are all the threads gonna be over-writing the same variable ?
for (int i = 0; i < persons.number; i++) //Loop all the people
var Dates = persons[i].Appointments.bydate(DateStep);
Do I need to worry about the Dates variable in the parallel loop ?
Sorry for the bad formatting of my question but it's only my second question and I'm getting there.
In short: No.
Because this variable is scoped inside the loop, it will be reassigned for every iteration of the loop anyways. It is not a value which is shared among different threads.
The only variables which you should worry about are those scoped outside of the loop.
Dates will be local to each loop iteration, so each thread will have a private copy on its own stack. No interference.
Be careful about variables declared outside the loop though.
Related
Many times I'm in front of a code like that:
var maybe = 'some random linq query'
int maybeCount = maybe.Count();
List<KeyValuePair<int, Customer>> lst2scan = maybe.Take(8).ToList();
for (int k = 0; k < 8; k++)
{
if (k + 1 <= maybeCount) custlst[k].Customer = lst2scan[k].Value;
else custlst[k].Customer = new Customer();
}
Each time I have a code like this. I ask me, must I create a variable to avoid the for-each calculate the Count() ?. Maybe for only 1 Count() in the loop it's useless.
Somebody have an advice with the "right way" to code that in a loop. Do you do in case per case or ?
In this case, is my maybeCount variable useless ?
Do you know if the Count() count each time or he just return the content of a count variable.
Thanks for any advice to improve my knowledge.
If the count is guarranteed to not change then yes this will stop the need to calculate the count multiple times, this can become more important when the Count is resolved from method that can take some time to execute.
If the count does change then this can result in erroneous results being generated.
In answer to your questions.
The way you have done it looks pretty reasonable
As mentioned, your cnt variable means that you won't have to repeat your linq query on each iteration.
The count will be determined each time you call it, it has no memory for what the count is
Note: It is important to note that I am talking about the Enumerable.Count method. The List<T>.Count is a property that can just return a value
Well, it depends ;)
I wouldn't use a loop. I would do something like this:
-
var maybe = 'some random linq query'
// if necessary clear list
custlst.Clear();
custlst.AddRange(maybe.Take(8).Select(p => p.Value));
custlst.AddRange(Enumerable.Range(0, 8 - custlst.Count).Select(i => new Customer()));
-
In this case, yes.
It depends if the underlying type is a List (a Collection, in fact) or a simple enumerable. The implementation of Count will look for a precomputed Count value and use it. So, if you're cycling a list, the variable is almost useless (still a little faster, but I don't think it's relevant by any means), if you're cycling a Linq query, a variable is recommended, because Count is going to cycle the entire enumeration.
Just my 2c.
Edit: for reference, you can find the source for .Count() at https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Enumerable.cs (around line 1489); as you see, it checks for ICollection, and uses the precomputed Count property.
I've read a number of other questions about Access to Modified closure so I understand the basic principle. Still, I couldn't tell - does Parallel.ForEach have the same issues?
Take the following snippet where I recompute the usage stats for users for the last week as an example:
var startTime = DateTime.Now;
var endTime = DateTime.Now.AddHours(6);
for (var i = 0; i < 7; i++)
{
// this next line gives me "Access To Modified Closure"
Parallel.ForEach(allUsers, user => UpdateUsageStats(user, startTime, endTime));
// move back a day and continue the process
startTime = startTime.AddDays(-1);
endTime = endTime.AddDays(-1);
}
From what I know of this code the foreach should run my UpdateUsageStats routine right away and start/end time variables won't be updated till the next time around the loop. Is that correct or should I use local variables to make sure there aren't issues?
You are accessing a modified closure, so it does apply. But, you are not changing its value while you are using it, so assuming you are not changing the values inside UpdateUsageStats you don't have a problem here.
Parallel.Foreach waits for the execution to end, and only then are you changing the values in startTime and endTime.
"Access to modified closure" only leads to problems if the capture scope leaves the loop in which the capture takes place and is used elsewhere. For example,
var list = new List<Action>();
for (var i = 0; i < 7; i++)
{
list.Add(() => Console.WriteLine(i));
}
list.ForEach(a => a()); // prints "7" 7 times, because `i` was captured inside the loop
In your case the lamda doing the capture doesn't leave the loop (the Parallel.ForEach call is executed completely within the loop, each time around).
You still get the warning because the compiler doesn't know whether or not Parallel.ForEach is causing the the lambda to be stored for later invocation. Since we know more than the compiler we can safely ignore the warning.
Consider the following snippet:
for(i = n-1; i >= 0; i--)
{
if(str[i] == ' ')
{
i += 2; // I am just incrementing it by 2, so that i can retrieve i+1
continue;
}
// rest of the code with many similar increments of i
}
Say suppose the loop never turns up into infinity and If I traverse through the loop with many such increments and decrements, I am sure the complexity would not be of order N or N Square. But is there any generalised complexity for such kind of solutions ??
P.S: I know it`s the worst code, but still wanted to give it a try :-)
This is an infinite loop (infinite complexity) if you have a space in your string. Since you are using continue, it goes back to for and it starts from i+2.
Lets assume that str does not change over the course of this traversal.
You are traversing str backwards and when you hit a space you move the index forward by one i.e. it would hit the space again in the next decrement and then move it forward again i.e. your claim that the loop is not infinite, does not seem valid.
If no mutable state affects the path taken by i, then either you go into an infinite loop, or you exit the loop in n or less steps. In the latter case, the worst case performance will be O(N).
If the loop mutates some other state, and that state affects the path, then it is impossible to predict the complexity without understanding the state and the mutation process.
(As written, the code will go into an infinite loop ... unless the section at the end of the loop does something to prevent it.)
I've seen this on occasion in books I've read. But I've found no explanation.
for (;;)
{
// Do some stuff.
}
Is it kind of like "while(true)"? Basically an endless loop for polling or something? Basically something you'd do until you intentionally break the loop?
Is it kind of like "while(true)"?
Yes. It loops forever.
Also note the comment by Andrew Coleson:
Languages like C don't have built-in boolean primitives, so some people prefer for(;;) over while(1)
Yes.
In a for if nothing is provided:
The initialisation does nothing.
The condition is always true
The count statement does nothing
It is equivalent to while(true).
You are correct. This is a common C# idiom for an endless loop.
Correct. Note that the braces of a for loop contain three parts:
Initialization code
A condition for continuing the loop
Something that gets executed for each loop iteration
With for(;;), all of these are empty, so there is nothing done to initialize the loop, there is no condition to keep it running (i.e. it will run indefinitely) and nothing that gets executed for each iteration except the loop's content.
Yes, It is an infinite loop.
If I recall correctly it's use over "while(true)", is it more resembles "for(;;) //ever"
Take a look at a for loop.
for ( initialization ; condition ; increment )
1) initialization - set a counter variable here
2) condition - keep looping until the counter variable meets the condition
3) increment - increment the counter
If there is no condition, a loop will go on forever. If it does such, then there is no need for a counter. Therefore
for(;;)
Yes, it's an endless loop, just like while(true).
It's the slightly preferred convention, probably because it's shorter.
There's no efficiency difference at all.
Loop forever.
Yes, it's an infinite loop. Same idea/effect as doing while(true) { ... }
Inifinite loop
like saying
while (0<1)
To be precise, any for loop without anything between the semicolons will loop forever (until terminated by some other means), because it has no defined invariant.
It doesn't have an end condition, so it will loop forever until it find a break, as you already guessed.
I might also add that it looks like 2 smiley faces winking at you
for (; ;)
maybe that's why some people like to use it.
Yes, it loops forever.
But the reason why you should use
for(;;)
instead of
while(true)
is that
while(true)
will give you a compiler warning "conditional expression constant", while the for-loop does not. At least you'll get such a compiler warning in the highest warning level.
Yes! .
Often used in embedded programming.
-setup interrupts and timers.
-then loop forever.
When an interrupt or timer occurs that will be handled.
I have a static array variable which is being shared by two threads.
I'd like to understand what happens if I assign the array variable to another array object in Thread1 while Thread2 is iterating over the array.
I.e
In thread 1
MyStaticClass.MyArray = SomeOtherArray
While in Thread 2:
for (int i = 0; i < MyStaticClass.MyArray.length; i++)
{
//do something with the i'th element
}
Assuming MyStaticClass.MyArray is just a field or simple property.
Nothing good or predictable will happen that's for sure.
I'd say most likely are:
The loop may read one half of old array and rest from new array
The new array may be shorter than the last giving a exception when you access [i]
Or Thread 2 may actually completely ignore the change to the array! And what's worse, this behaviour may be different in Release build to Debug.
The last situation is due to compiler optimisations and/or the way the memory model works in .net (and other languages like Java BTW). There's a whole keyword to get around this issue (volatile) http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/
To prevent this, you want to use a lock to lock the critical section. Basically wrapping your itteration in a lock will prevent the other thread from overwriting the array while you are processing it
The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section. If another thread tries to enter a locked code, it will wait, block, until the object is released.
https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
The condition in your for loop is evaluated for every iteration. So if another thread changes the reference in MyStaticClass.MyArray, you use this new reference in the next iteration.
For example, this code:
int[] a = {1,2,3,4,5};
int[] b = {10, 20, 30, 40, 50, 60, 70};
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i]);
a = b;
}
gives this output:
1
20
30
40
50
60
70
To avoid this, you could use foreach:
foreach(int c in a)
{
Console.WriteLine(c);
a = b;
}
gives:
1
2
3
4
5
because foreach is translated so that it calls a.GetEnumerator() once and then uses this enumerator (MoveNext() and Current) for all iterations, not accessing a again.
There will be no consequences other than thread 2 at some point starting to work on the new array instead of the old. When exactly this happens is more or less random, and as weston writes in his comment, it may never even happen at all.
If the new array has fewer elements than the old one this can (but doesn't have to) cause a runtime exception.