title: Async threadsafe Get from MemoryCache
body: <p>I have created a async cache that uses .NET <code>MemoryCache</code> underneath.
  This is the code:</p>
  
  <pre><code>public async Task&lt;T&gt; GetAsync(string key, Func&lt;Task&lt;T&gt;&gt; populator, TimeSpan expire, object parameters)
  {
      if(parameters != null)
          key += JsonConvert.SerializeObject(parameters);
  
      if(!_cache.Contains(key))
      {
          var data = await populator();
          lock(_cache)
          {
              if(!_cache.Contains(key)) //Check again but locked this time
                  _cache.Add(key, data, DateTimeOffset.Now.Add(expire));
          }
      }
  
      return (T)_cache.Get(key);
  }
  </code></pre>
  
  <p>I think the only downside is that I need to do the await outside the lock so the populator isn't thread safe, but since the await can't reside inside a lock I guess this is the best way. Are there any pitfalls that I have missed?</p>
  
  <p><strong>Update</strong>: A version of Esers answer that is also threadsafe when another thread invalidates the cache:</p>
  
  <pre><code>public async Task&lt;T&gt; GetAsync(string key, Func&lt;Task&lt;T&gt;&gt; populator, TimeSpan expire, object parameters)
  {
      if(parameters != null)
          key += JsonConvert.SerializeObject(parameters);
  
      var lazy = new Lazy&lt;Task&lt;T&gt;&gt;(populator, true);
      _cache.AddOrGetExisting(key, lazy, DateTimeOffset.Now.Add(expire));
      return ((Lazy&lt;Task&lt;T&gt;&gt;) _cache.Get(key)).Value;
  }
  </code></pre>
  
  <p>It can however be slower because it creates Lazy instances that never will be executed and it uses Lazy in full threadsafe mode <code>LazyThreadSafetyMode.ExecutionAndPublication</code></p>
  
  <p><strong>Update with new benchmark (Higher is better)</strong></p>
  
  <pre><code>Lazy with lock      42535929
  Lazy with GetOrAdd  41070320 (Only solution that is completely thread safe)
  Semaphore           64573360
  </code></pre>