Anatoly
Anatoly

Reputation: 1916

How to return a data before method complete execution?

I have a slow and expensive method that return some data for me:

public Data GetData(){...}

I don't want to wait until this method will execute. Rather than I want to return a cached data immediately.

I have a class CachedData that contains one property Data cachedData. So I want to create another method public CachedData GetCachedData() that will initiate a new task(call GetData inside of it) and immediately return cached data and after task will finish we will update the cache.

I need to have thread safe GetCachedData() because I will have multiple request that will call this method.

I will have a light ping "is there anything change?" each minute and if it will return true (cachedData != currentData) then I will call GetCachedData().

I'm new in C#. Please, help me to implement this method.

I'm using .net framework 4.5.2

Upvotes: 1

Views: 313

Answers (3)

Erkan Demirel
Erkan Demirel

Reputation: 4382

If you will not call GetCachedData at the same time, you may not use lock. If data is null (for sure first run) we will wait long method to finish its work.

public class SlowClass
{
    private static object _lock;
    private static Data _cachedData;
    public SlowClass()
    {
        _lock = new object();
    }

    public void GetCachedData()
    {
        var task = new Task(DoStuffLongRun);
        task.Start();
        if (_cachedData == null)
            task.Wait();
    }

    public Data GetData()
    {
        if (_cachedData == null)
            GetCachedData();
        return _cachedData;
    }
    private void DoStuffLongRun()
    {

        lock (_lock)
        {
            Console.WriteLine("Locked Entered");
            Thread.Sleep(5000);//Do Long Stuff
            _cachedData = new Data();
        }

    }
}

I have tested on console application.

 static void Main(string[] args)
    {

        var mySlow = new SlowClass();
        var mySlow2 = new SlowClass();
        mySlow.GetCachedData();
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine(i);
            mySlow.GetData();
            mySlow2.GetData();
        }
        mySlow.GetCachedData();
        Console.Read();
    }

Upvotes: 1

Peter - Reinstate Monica
Peter - Reinstate Monica

Reputation: 16017

The basic idea is clear:

  • You have a Data property which is wrapper around an expensive function call.
  • In order to have some response immediately the property holds a cached value and performs updating in the background.
  • No need for an event when the updater is done because you poll, for now.

That seems like a straight-forward design. At some point you may want to use events, but that can be added later.

Depending on the circumstances it may be necessary to make access to the property thread-safe. I think that if the Data cache is a simple reference and no other data is updated together with it, a lock is not necessary, but you may want to declare the reference volatile so that the reading thread does not rely on a stale cached (ha!) version. This post seems to have good links which discuss the issues.

Upvotes: 2

AllWorkNoPlay
AllWorkNoPlay

Reputation: 454

Maybe you can use the MemoryCache class, as explained here in MSDN

Upvotes: -1

Related Questions