Groups | Blog | Home
all groups > c# > march 2008 >

c# : Evaluate LINQ immediately


Peter Morris
3/5/2008 9:48:21 PM
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

Jon Skeet [C# MVP]
3/6/2008 8:35:51 AM
[quoted text, click to view]

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

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Peter Morris
3/6/2008 9:52:50 AM
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

Jon Skeet [C# MVP]
3/6/2008 10:16:39 AM
[quoted text, click to view]

Ah, right. Yes, I can see how that could happen :)

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Jon Skeet [C# MVP]
3/7/2008 7:54:37 AM
On Mar 7, 3:45 pm, Christopher Van Kirk <chris.vank...@fdcjapan.com>
[quoted text, click to view]

<snip>

[quoted text, click to view]

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 Skeet [C# MVP]
3/7/2008 5:04:17 PM
[quoted text, click to view]

<snip>

[quoted text, click to view]

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.)

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Christopher Van Kirk
3/8/2008 12:45:14 AM
On Wed, 5 Mar 2008 21:48:21 -0000, "Peter Morris"
[quoted text, click to view]

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.

--
Posted via a free Usenet account from http://www.teranews.com
Christopher Van Kirk
3/8/2008 1:49:44 AM
On Fri, 7 Mar 2008 07:54:37 -0800 (PST), "Jon Skeet [C# MVP]"
[quoted text, click to view]

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[i] < count / 2)
{
newList.Add(ints[i]);
}
}
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.

--
Posted via a free Usenet account from http://www.teranews.com
AddThis Social Bookmark Button