Evaluate LINQ immediately

  • Thread starter Thread starter Peter Morris
  • Start date Start date
P

Peter Morris

from line in order.Lines
select new { Number = line.Number, Qty = line.Quantity }

at this point I deactivate my object cache, which is where line.Number and
line.Quantity are read from, so any subsequent attempts to read those
properties will result in an InvalidOperationException.

So to avoid this I need the anonymous objects created immediately so that no
further attempt is made to read the objects' properties. How would this be
done?

I tried

var lines = select.......;
lines = lines.ToArray();

but that didn't do the trick either.


Can someone tell me how I would achieve this?


Thanks

Pete
 
from line in order.Lines
select new { Number = line.Number, Qty = line.Quantity }

at this point I deactivate my object cache, which is where line.Number and
line.Quantity are read from, so any subsequent attempts to read those
properties will result in an InvalidOperationException.

So to avoid this I need the anonymous objects created immediately so that no
further attempt is made to read the objects' properties. How would this be
done?

I tried

var lines = select.......;
lines = lines.ToArray();

but that didn't do the trick either.

In what way? That would certainly have executed the query immediately.
(I prefer ToList myself, but...)
 
Aha!

It turns out I was getting a null reference exception for two different
reasons.

Reason 01: Lazy evaluation after the object cache was deactivated.
Solution, use ToArray on the result.
Reason 02: AutoInc property on my class. Solution, don't try to show the
child list unless the parent object has been saved.

#02 is due to the fact that AutoInc properties are assigned by the DB and
are therefore null until the object has been saved. Because the error
message was the same I mistakenly thought it was the result of the same
error.


Thanks :-)



Pete
 
Aha!

It turns out I was getting a null reference exception for two different
reasons.

Reason 01: Lazy evaluation after the object cache was deactivated.
Solution, use ToArray on the result.
Reason 02: AutoInc property on my class. Solution, don't try to show the
child list unless the parent object has been saved.

#02 is due to the fact that AutoInc properties are assigned by the DB and
are therefore null until the object has been saved. Because the error
message was the same I mistakenly thought it was the result of the same
error.

Ah, right. Yes, I can see how that could happen :)
 
from line in order.Lines
select new { Number = line.Number, Qty = line.Quantity }

at this point I deactivate my object cache, which is where line.Number and
line.Quantity are read from, so any subsequent attempts to read those
properties will result in an InvalidOperationException.

So to avoid this I need the anonymous objects created immediately so that no
further attempt is made to read the objects' properties. How would this be
done?

I tried

var lines = select.......;
lines = lines.ToArray();

but that didn't do the trick either.


Can someone tell me how I would achieve this?


Thanks

Pete

Tangentially, have you looked at the performance of LINQ versus a
similar set of customized code? LINQ looked very attractive to me
until I tried to benchmark it in that way.
 
On Mar 7, 3:45 pm, Christopher Van Kirk <[email protected]>
wrote:

Tangentially, have you looked at the performance of LINQ versus a
similar set of customized code? LINQ looked very attractive to me
until I tried to benchmark it in that way.

So you've said before, but with *no* details of what you were trying
to do.

As Frans and I discussed (in the same thread) there are certainly
things you could try to do in LINQ to SQL (it's worth specifying which
flavour of LINQ you mean when talking about it, btw) which would give
bad performance, but dismissing the *whole* of LINQ to SQL performance
as poor is a bad idea, IMO.

Search for LINQ in http://blogs.msdn.com/ricom/ for some concrete
figures about LINQ to SQL performance in specific situations.

Jon
 
On Mar 7, 3:45 pm, Christopher Van Kirk <[email protected]>
wrote:



So you've said before, but with *no* details of what you were trying
to do.

As Frans and I discussed (in the same thread) there are certainly
things you could try to do in LINQ to SQL (it's worth specifying which
flavour of LINQ you mean when talking about it, btw) which would give
bad performance, but dismissing the *whole* of LINQ to SQL performance
as poor is a bad idea, IMO.

Search for LINQ in http://blogs.msdn.com/ricom/ for some concrete
figures about LINQ to SQL performance in specific situations.

Jon

I did two tests. The first, below, ordered a list of ints. The ints
themselves were generated randomly, and in no partcular order.

private void button1_Click(object sender, EventArgs e)
{

int i = 0, count = 1000000;

IList<int> ints = this.GenerateInts(count),
linqed = new List<int>(),
sorted;

int[] ordinals;

double orderby,
firstelement,
nextelement,
total,
sorterQuick,
sorterHeap,
sorterMerge,
sorterInsert;

orderby = firstelement = nextelement = total = sorterQuick
= sorterHeap = sorterMerge = 0;

HighPerformanceTimer timer1 = new HighPerformanceTimer(),
timer2 = timer1.Clone() as HighPerformanceTimer;

timer1.Start();
timer2.Start();

var a = ints.OrderBy( p => p, Comparer<int>.Default );

timer1.Stop();

orderby = timer1.ElapsedSeconds();

timer1.Start();

foreach (int val in a)
{
if (i == 0)
{
timer1.Stop();
firstelement = timer1.ElapsedSeconds();
timer1.Start();
}
else
{
if (i == 1)
{
timer1.Stop();
nextelement = timer1.ElapsedSeconds();
}
}
linqed.Add(val);
i++;
}

timer2.Stop();
total = timer2.ElapsedSeconds();

System.Diagnostics.Debug.Print("Passed Linq sort
orderby={0}, firstelement={1}, nextelement={2}, total={3}", orderby,
firstelement, nextelement, total );

ordinals = Sorter.GetOrdinals(count);
timer1.Start();
sorted = Sorter.SortPointers<int>( ordinals, ints,
SortMethod.HugeQuick);
timer1.Stop();

sorterQuick = timer1.ElapsedSeconds();
System.Diagnostics.Debug.Print("Passed quick sort {0}",
sorterQuick);

ordinals = Sorter.GetOrdinals(count);
timer1.Start();
sorted = Sorter.SortPointers<int>( ordinals, ints,
SortMethod.Heap);
timer1.Stop();

sorterHeap = timer1.ElapsedSeconds();
System.Diagnostics.Debug.Print("Passed heap sort {0}",
sorterHeap);

ordinals = Sorter.GetOrdinals(count);
timer1.Start();
sorted = Sorter.SortPointers<int>( ordinals, ints,
SortMethod.Merge);
timer1.Stop();

sorterMerge = timer1.ElapsedSeconds();
System.Diagnostics.Debug.Print("Passed merge sort {0}",
sorterMerge);

}


This produced the following output:

Passed Linq sort orderby=1.36772072165396E-06,
firstelement=0.507163260675607, nextelement=1.70756239620126E-06,
total=0.577546772172414
Passed quick sort 0.459738433186191
Passed heap sort 1.21546727261184
Passed merge sort 0.763105243653448


I took this to mean that an order by operation is about 25% slower via
LINQ than doing a comparable quicksort.


The second test was filtering. The code for this is here:


private void button2_Click(object sender, EventArgs e)
{
int i = 0, count = 1000000;

IList<int> ints = this.GenerateInts(count),
linqed = new List<int>();

double whereclause,
sortthencustomfilter,
customfilter;

whereclause = sortthencustomfilter = customfilter = 0;

HighPerformanceTimer timer1 = new HighPerformanceTimer();

timer1.Start();

var a = ints.Where(p => p > count/2);

foreach (int val in a)
{
linqed.Add(val);
i++;
}

timer1.Stop();
whereclause = timer1.ElapsedSeconds();

System.Diagnostics.Debug.Print("Passed Linq where filter:
whereclause={0}", whereclause);

timer1.Start();
IList<int> newList = new List<int>();

for (i = 0; i < count; i++)
{
if (ints < count / 2)
{
newList.Add(ints);
}
}
timer1.Stop();

customfilter = timer1.ElapsedSeconds();
System.Diagnostics.Debug.Print("Passed filter only in {0},
difference={1}", customfilter, 1-customfilter/whereclause);
}


and the output here:

Passed Linq where filter: whereclause=0.030069347417103
Passed filter only in 0.018763416394604, difference=0.375995224162012


LINQ is 37% slower at picking out elements from a list was what I got
out of this.


At this point I quit looking at it. For my purposes, losing double
digit percentages off performance just isn't acceptable. I suppose
that might be acceptable to others, though.
 
LINQ is 37% slower at picking out elements from a list was what I got
out of this.

At this point I quit looking at it. For my purposes, losing double
digit percentages off performance just isn't acceptable. I suppose
that might be acceptable to others, though.

It's certainly more than acceptable in most cases for me. How often is
the performance of this sort of code actually a bottleneck for you?
It's almost never a bottleneck for me (or most people, I'd suggest) -
whereas the expressive power LINQ provides is huge.

It shouldn't come as a shock that invoking a delegate is slower than
executing inlined code, really. Try making your filter more general and
then see what happens.

(You might want to see how much of the time is spent adding values to
the list, by the way... using IEnumerable<T> and deferred execution is
often more efficient than buffering the whole result in a list.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top