caching the result from a [n async] factory method iff it doesn't throw
Does this get anywhere near your requirements?
The behaviour falls somewhere between ExecutionAndPublication
and PublicationOnly
.
While the initializer is in-flight all calls to Value
will be handed the same task (which is cached temporarily but could subsequently succeed or fail); if the initializer succeeds then that completed task is cached permanently; if the initializer fails then the next call to Value
will create a completely new initialization task and the process begins again!
public sealed class TooLazy<T>
{
private readonly object _lock = new object();
private readonly Func<Task<T>> _factory;
private Task<T> _cached;
public TooLazy(Func<Task<T>> factory)
{
if (factory == null) throw new ArgumentNullException("factory");
_factory = factory;
}
public Task<T> Value
{
get
{
lock (_lock)
{
if ((_cached == null) ||
(_cached.IsCompleted && (_cached.Status != TaskStatus.RanToCompletion)))
{
_cached = Task.Run(_factory);
}
return _cached;
}
}
}
}
How to cache data as long as Task executes?
Let's say, we have the first call GetDefaultData (GetData() executes in 100ms), and then we have 10 calls(GetDefaultData() per 10ms). I want that this rest of calls will get the same answer as the first one.
It sounds like you want the Lazy<T>
class.
public class YourClass
{
private readonly Lazy<Data> _lazyData;
public YourClass()
{
_lazyData = new Lazy<Data>(() => GetData());
}
private Data GetDefaultData()
{
return _lazyData.Value;
}
public Data GetData()
{
//...
}
}
The first thread to call GetDefaultData()
will run GetData()
when it hits _lazyData.Value
, all the rest of the threads will block on the call _lazyData.Value
till the first thread finishes and use the result from that first thread's call. GetData()
will only ever be called once.
If you don't want the call to block you can easily make a AsyncLazy<T>
class that uses Threads internally.
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{
}
public AsyncLazy(Func<Task<T>> taskFactory, bool runFactoryInNewTask = true) :
base(() => runFactoryInNewTask ? Task.Run(taskFactory) : taskFactory())
{
}
//This lets you use `await _lazyData` instead of doing `await _lazyData.Value`
public TaskAwaiter<T> GetAwaiter()
{
return Value.GetAwaiter();
}
}
Then your code becomes (I also made GetData an async function too, but the overloads of AsyncLazy
let it be either or)
public class YourClass
{
private readonly AsyncLazy<Data> _lazyData;
public YourClass()
{
_lazyData = new AsyncLazy<Data>(() => GetData(), false);
}
private async Task<Data> GetDefaultData()
{
//I await here to defer any exceptions till the returned task is awaited.
return await _lazyData;
}
public Task<Data> GetData()
{
//...
}
}
EDIT: There are some possible issues with AsyncLazy, see here.
Avoiding all DI antipatterns for types requiring asynchronous initialization
This is a long answer. There's a summary at the end. Scroll down to the summary if you're in a hurry.
The problem you have, and the application you're building, is a-typical. It’s a-typical for two reasons:
- you need (or rather want) asynchronous start-up initialization, and
- Your application framework (azure functions) supports asynchronous start-up initialization (or rather, there seems to be little framework surrounding it).
This makes your situation a bit different from a typical scenario, which might make it a bit harder to discuss common patterns.
However, even in your case the solution is rather simple and elegant:
Extract initialization out of the classes that hold it, and move it into the Composition Root. At that point you can create and initialize those classes before registering them in the container and feed those initialized classes into the container as part of registrations.
This works well in your particular case, because you want to do some (one-time) start-up initialization. Start-up initialization is typically done before you configure the container (or sometimes after if it requires a fully composed object graph). In most cases I’ve seen, initialization can be done before, as can be done effectively in your case.
As I said, your case is a bit peculiar, compared to the norm. The norm is:
- Start-up initialization is synchronous. Frameworks (like ASP.NET Core¹) typically do not support asynchronous initialization in the start-up phase.
- Initialization often needs to be done per-request and just-in-time rather than per-application and ahead-of-time. Often components that need initialization have a short lifetime, which means we typically initialize such instance on first use (in other words: just-in-time).
There is usually no real benefit of doing start-up initialization asynchronously. There is no practical performance benefit because, at start-up time, there will only be a single thread running anyway (although we might parallelize this, that obviously doesn’t require async). Also note that although some application types might deadlock on doing synch-over-async, in the Composition Root we know exactly which application type we are using and whether or not this will be a problem or not. A Composition Root is always application-specific. In other words, when we have initialization in the Composition Root of a non-deadlocking application (e.g. ASP.NET Core, Azure Functions, etc), there is typically no benefit of doing start-up initialization asynchronously, except perhaps for the sake of sticking to the advised patterns & practices.
Because you know whether or not sync-over-async is a problem or not in your Composition Root, you could even decide to do the initialization on first use and synchronously. Because the amount of initialization is finite (compared to per-request initialization) there is no practical performance impact on doing it on a background thread with synchronous blocking if you wish. All you have to do is define a Proxy class in your Composition Root that makes sure that initialization is done on first use. This is pretty much the idea that Mark Seemann proposed as answer.
I was not familiar at all with Azure Functions, so this is actually the first application type (except Console apps of course) that I know of that actually supports async initialization. In most framework types, there is no way for users to do this start-up initialization asynchronously at all. Code running inside an Application_Start
event in an ASP.NET application or in the Startup
class of an ASP.NET Core application, for instance, there is no async. Everything has to be synchronous.
On top of that, application frameworks don’t allow you to build their framework root components asynchronously. So even if DI Containers would support the concept of doing asynchronous resolves, this wouldn’t work because of the ‘lack’ of support of application frameworks. Take ASP.NET Core’s IControllerActivator
for instance. Its Create(ControllerContext)
method allows you to compose a Controller
instance, but the return type of the Create
method is object
, not Task<object>
. In other words, even if DI Containers would provide us with a ResolveAsync
method, it would still cause blocking because ResolveAsync
calls would be wrapped behind synchronous framework abstractions.
In the majority of cases, you’ll see that initialization is done per-instance or at runtime. A SqlConnection
, for instance, is typically opened per request, so each request needs to open its own connection. When you want to open the connection ‘just in time’, this inevitably results in application interfaces that are asynchronous. But be careful here:
If you create an implementation that is synchronous, you should only make its abstraction synchronous in case you are sure that there will never be another implementation (or proxy, decorator, interceptor, etc.) that is asynchronous. If you invalidly make the abstraction synchronous (i.e. have methods and properties that do not expose Task<T>
), you might very well have a Leaky Abstraction at hand. This might force you to make sweeping changes throughout the application when you get an asynchronous implementation later on.
In other words, with the introduction of async
you have to take even more care of the design of your application abstractions. This holds for your specific case as well. Even though you might only require start-up initialization now, are you sure that for the abstractions you defined (and AzureConnections
as well) will never need just-in-time synchronous initialization? In case the synchronous behavior of AzureConnections
is an implementation detail, you will have to make it async right away.
Another example of this is your INugetRepository. Its members are synchronous, but that is clearly a Leaky Abstraction, because the reason it is synchronous is because its implementation is synchronous. Its implementation, however, is synchronous because it makes use of a legacy NuGet package that only has a synchronous API. It’s pretty clear that INugetRepository
should be completely async, even though its implementation is synchronous, because implementations are expected to communicate over the network, which is where asynchronicity makes sense.
In an application that applies async, most application abstractions will have mostly async members. When this is the case, it would be a no-brainer to make this kind of just-in-time initialization logic async as well; everything is already async.
Summary
- In case you need start-up initialization: do it before or after configuring the container. This makes composing object graphs itself fast, reliable, and verifiable.
- Doing initialization before configuring the container prevents Temporal Coupling, but might mean you will have to move initialization out of the classes that require it (which is actually a good thing).
- Async start-up initialization is impossible in most application types. In the other application types it is typically unnecessary.
- In case you require per-request or just-in-time initialization, there is no way around having asynchronous interfaces.
- Be careful with synchronous interfaces if you’re building an asynchronous application, you might be leaking implementation details.
Footnotes
- ASP.NET Core actually does allow async start-up initialization, but not from within the
Startup
class. There are several ways to achieve this: either you implement and register hosted services that contain (or delegate to) the initialization, or trigger the async initialization from within theasync Main
method of the program class.
Does using lazy evaluation when inserting into a ConcurrentDictionary prevent the requested value from being calculated multiple times?
GetOrAdd
will always return the same value. Two threads may race to create a Lazy<R>
for the same argument value, but they'll both end up with a reference to only one of them. They'll both in turn call Value
on it and it will do its own initialization once. It's only the call to Value
that forces this initialization to occur, and it's only then that func(a)
is invoked.
The other Lazy<R>
will be abandoned and will eventually be GCed1 without ever being asked to initialize its value.
1Assuming the GC runs at all in the future, you're not running with a null GC, etc.
Is Task == Lazy?
Similarities
Both Lazy<T>
and Task<T>
promise to do some work later and return a result of type T
.
Differences
Lazy<T>
promises to do its work as late as possible if it is required at all, and does so synchronously.
Task<T>
however can do its work asynchronously while your thread does other work, or blocks awaiting result.
Lazy<T>
will bubble up any exception caused by the lambda when you call .Value
.
Task<T>
will keep any exception caused by the lambda and throw it later when you await task
. Or if you task.Wait()
it may wrap the exception in an AggregationException
. I refer you to this for more info on catching exceptions thrown by tasks: Catch an exception thrown by an async method and this http://stiller.co.il/blog/2012/12/task-wait-vs-await/
How to call an async method from a getter or setter?
I really needed the call to originate from the get method, due to my decoupled architecture. So I came up with the following implementation.
Usage: Title is in a ViewModel or an object you could statically declare as a page resource. Bind to it and the value will get populated without blocking the UI, when getTitle() returns.
string _Title;
public string Title
{
get
{
if (_Title == null)
{
Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); });
}
return _Title;
}
set
{
if (value != _Title)
{
_Title = value;
RaisePropertyChanged("Title");
}
}
}
Lazy load properties with Async
First of all, properties with side-effects are usually not all that good.
In this case, simply reading this property would kick off a thread, some network traffic, and some processing on a remote server.
This should be a method, not a property.
Secondly, the compiler is right, properties are not allowed to be asynchronous. Now, you can definitely write a property that returns an asynchronous task, but you're not allowed to use the async
keyword. Basically just take away the async
keyword from the property declaration.
But the fact that async
is not legal on properties is another clue that you should write a method, not a property.
Note The (Removed after OP edited the question.)async
keyword is not actually required in the code you've posted, since you're not actually using the await
keyword in there. As such, you can simply remove the async
keyword altogether, since it is not required. In fact, if you were to change this over to a method, the compiler will tell you that it is unnecessary since you're not using await
.
LazyT without exception caching
It's hard to use built-in Lazy for that: you should wrap your LazyWithoutExceptionCaching.Value getter in a lock. But that makes the use of the built-in Lazy
redundant: you'll have unnecessary locks inside the Lazy.Value
getter.
It's better to write your own Lazy implementation especially
if you intend to instantiate reference types only, it turns to be rather simple:
public class SimpleLazy<T> where T : class
{
private readonly Func<T> valueFactory;
private T instance;
private readonly object locker = new object();
public SimpleLazy(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
this.instance = null;
}
public T Value
{
get
{
lock (locker)
return instance ?? (instance = valueFactory());
}
}
}
P.S. Maybe we'll have this functionality built-in when this issue gets closed.
Lazy initialization
From Reflector:
public Lazy(Func<T> valueFactory, bool isThreadSafe) : this(valueFactory, isThreadSafe ?LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
{
}
So if you pass true
it will convert to LazyThreadSafetyMode.ExecutionAndPublication
.
false
will convert to LazyThreadSafetyMode.None
By the way, if you only pass the value factor (omitting the bool altogether), it uses LazyThreadSafetyMode.ExecutionAndPublication
.
Related Topics
Access Visual Studio 2017's Private Registry Hive
How to Handle Forms Authentication Timeout Exceptions in ASP.NET
Opening a "Known File Type" into Running Instance of Custom App - .Net
How to Have an Optional Parameter for an ASP.NET Soap Web Service
C# Datetimes: Conversion for Different Time Zones
Use Linq to Generate Direct Update Without Select
Comparing 2 Objects and Retrieve a List of Fields with Different Values
Convert String Value to Operator in C#
How Does Deferred Linq Query Execution Actually Work
Linq - What Is the Quickest Way to Find Out Deferred Execution or Not
C#: How to Add Subitems in Listview
Using Sse in C# Is It Possible
Print Fixeddocument/Xps to PDF Without Showing File Save Dialog