This news went mostly unnoticed but that’s actually a big one, at least for those of us who uses NHibernate as their primary ORM: NHibernate 5 now supports async IO bound operations.
NHibernate 5: async IO bound operations support
This feature is one of the few that NHibernate lacked and other ORMs (Entity Framework, Dapper) didn’t. It’s great to see that this gap is closed now.
If you wonder what’s the deal with async IO bound operations, here’s a quick explanation. When doing IO bound work (such as reading from a file, sending a request via the Internet, etc.), you don’t want to consume threads of your server’s thread pool because this work doesn’t actually involve CPU. Executing such operations on a thread means this thread would just sit idle and wait until the IO operations are finished. To avoid this, you need to delegate this work to the appropriate driver, register a callback with the IO Completion Port, release the working thread, and resume processing on it only after the work is completed and the callback is called. This allows you to increase the application’s throughput and avoid such nasty things as thread starvation (or at least delay it).
The communication with the database falls into this category as your application talks to it via the server’s network adapter. And so it’s a good idea to use async operations for that too.
Entity Framework has been supporting this feature for quite a long time already. Now you can do that with NHibernate as well. All operations that involve IO work have received an async counterpart.
Here’s how you can load an entity from the database:
Get a “shadow” entity with only Id initialized:
Get a list of entities via a LINQ query:
Load it using an HQL query:
Note that this feature is not intended for parallelism, only non-parallel asynchrony, so make sure to await each call before issuing a new call using the same session.
In other words, don’t do this:
Do this instead:
A quick side note about parallelism versus asynchrony. Parallel execution is a subset of asynchronous execution: every parallel execution is asynchronous, but not every asynchronous execution is parallel.
Executing something asynchronously corresponds to “without blocking the caller”. It can be achieved by starting this work immediately, which means it will be done in parallel, or by waiting until the caller is finished with their stuff, which means the work will be executed sequentially, either by the same or another thread. Either way, the job will not block the caller and thus we can say that it will be executed asynchronously.
Finally, here’s an example of updating an entity:
Querying entity collections
There’s another interesting feature in this release. Now you can query an entity’s collection without fully loading it, like so:
NHibernate will generate a query which only retrieves the customer’s orders that fit the criteria. Pretty nice.