суббота, 27 февраля 2010 г.

EqualityComparer for C# 3.0 Expressions

.NET Expression classes let us perform only reference equality checks on them. But sometimes we need to check the true value equality.  As part of my attempt to build autocacher for LINQ TO SQL compiled queries I created an equality comparer that implements IEqualityComparer<Expression> interface. It lets me, for example, to use an Expression as a key in a dictionary. The implementation is .NET 3.5 specific  and based on the example ExpressionVisitor class from MSDN. As a bonus  there are extensions to the Expression class in the project so that you can visit and rewrite  expressions without deriving from ExpressionVisitor. It can be very handy in simple scenarios.

ExpressionEqualityComparer.zip

p.s. BTW in .NET 4.0 they made  the ExpressionVistor class public.  In .NET 3.5 it  was internal.

среда, 10 февраля 2010 г.

LINQ TO SQL and asynchronous IO

LINQ TO SQL doesn’t inherently support asynchronous IO. It is unfortunate, because non-blocking IO is a way to get great scalability on server side whether you do it directly with APM,   CCR Iterators  and APM adaptors, Jeffrey Richter's AsyncEnumerator, TPL iterators'  integration with APM,  or even Axum which natively recognizes APM methods.

Well there is actually a small hole through which we can use APM but in a very restrictive way.
The best  tool to experiment with L2S is LinqPAD. Point it at Northwind database and try next “statement” query:

var query = from e in Employees
   where e.EmployeeID == 1
   select e;

System.Data.Common.DbCommand cmd = this.GetCommand(query);
try
{
 this.Connection.Open();
 System.Data.Common.DbDataReader reader = cmd.ExecuteReader();
 IEnumerable employees = this.Translate(reader);
 
 //using results
 Employees employee = employees.First();
 employee.Dump();
}
finally
{
 this.Connection.Close();
}

Instead of ExecuteReader we can use BeginExecuteReader and EndExecuteReader methods.  Wrap it in an convenient extension method for DataContext class and it seams we solved the problem. No.. Here is the list of problems we still have:

  • eager loading of many-to-one and one-to-many relations of the  entity in question doesn’t work with our method
  • to fulfil some queries L2S has to send more than one SQL commands to the server, but DataContext.GetCommand returns only the first one
  • L2S doesn’t support asynchronous lazy loading of  many-to-one, one-to-many  and Link<T> based properties of an entity
  • L2S doesn’t support asynchronous compiled queries
  • besides querying L2S doesn’t support  submitting changes asynchronously
  • and don’t forget about transactions

The list looks like a show stopper. But if you really  need to use APM with L2S and are not going to  eager load relations of the entity you want to query and sure that your  query will generate only one SQL command and won’t be surrounded by a transaction then you  should use it because parallelism and asynchronicity  is the way to performance and scalability.

воскресенье, 7 февраля 2010 г.

.NET threads and stack memory

Normally when an unmanaged thread is created 1 MB of virtual address space is reserved and 4 KB (a page) is committed for its stack. Reserved here is an important word, because reservation allocates no physical storage but only well.. reserves a range of virtual memory.  It guaranties continuousness of the memory required for threads’ stacks. Allocation of the real storage (committing) happens as the stack grows, page by page. 
But as address space in a process is usually limited by 2 GB  the more threads you create the less virtual address space is left. For example, a thousand of threads can consume a half of the available  virtual memory of the process. 
But recently I have found that the things are different in the managed world. When a managed thread created  1 MB of memory is reserved and committed for its stack before it starts. There is no difference between a managed thread and an unmanaged one regarding virtual memory space consuming but the early committing  brings the whole system closer to the commit limit which is “the sum of physical memory and the sizes of the paging files”.
It is one more reason not to create threads if you can. Use ThreadPool, Tasks or  async IO instead.

You can read more about the reasons behind the CLR team’s decision,
what Windows memory limits are and how  Processes and Threads consume memory.