c# - Async threadsafe Get from MemoryCache -


i have created async cache uses .net memorycache underneath. code

public async task<t> getasync(string key, func<task<t>> 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 locked time                 _cache.add(key, data, datetimeoffset.now.add(expire));         }     }      return (t)_cache.get(key); } 

i think downside need todo await outside lock populator isnt thread safe, since await cant reside inside lock guess best way. there pitfalls have missed?

update: version of esers answer threadsafe when antoher thread invalidates cache

public async task<t> getasync(string key, func<task<t>> populator, timespan expire, object parameters) {     if(parameters != null)         key += jsonconvert.serializeobject(parameters);      var lazy = new lazy<task<t>>(populator, true);     _cache.addorgetexisting(key, lazy, datetimeoffset.now.add(expire));     return ((lazy<task<t>>) _cache.get(key)).value; } 

it can slower because creates lazy instances never executed , uses lazy in full threadsafe mode lazythreadsafetymode.executionandpublication

update new benchmark (higher better)

lazy lock      42535929 lazy getoradd  41070320 (only solution thread safe) semaphore           64573360 

a simple solution use semaphoreslim.waitasync() instead of lock, , around issue of awaiting inside lock. although, other methods of memorycache thread-safe.

private semaphoreslim semaphoreslim = new semaphoreslim(1); public async task<t> getasync(             string key, func<task<t>> populator, timespan expire, object parameters) {     if (parameters != null)         key += jsonconvert.serializeobject(parameters);      if (!_cache.contains(key))     {         await semaphoreslim.waitasync();         try         {             if (!_cache.contains(key))             {                 var data = await populator();                 _cache.add(key, data, datetimeoffset.now.add(expire));             }         }                 {             semaphoreslim.release();         }     }      return (t)_cache.get(key); } 

Comments

Popular posts from this blog

python - pip install -U PySide error -

arrays - C++ error: a brace-enclosed initializer is not allowed here before ‘{’ token -

cytoscape.js - How to add nodes to Dagre layout with Cytoscape -