How to return the result from a task?

I have the following methods:

public int getData() { return 2; } // suppose it is slow and takes 20 sec // pseudocode public int GetPreviousData() { Task<int> t = new Task<int>(() => getData()); return _cachedData; // some previous value _cachedData = t.Result; // _cachedData == 2 } 

I do not want to wait for the result of an already running operation.

I want to return _cachedData and update it after Task completes.

How to do it? I am using .net framework 4.5.2

+5
source share
3 answers

Here you can use the out parameter:

 public Task<int> GetPreviousDataAsync(out int cachedData) { Task<int> t = Task.Run(() => getData()); cachedData = _cachedData; // some previous value return t; // _cachedData == 2 } int cachedData; cachedData = await GetPreviousDataAsync(out int cachedData); 

Pay attention to the Task.Run object: it starts the task using the thread pool and returns a Task<int> so that the caller can decide whether to wait, continue, or start and forget it.

See the following example. I redid everything into a class:

 class A { private int _cachedData; private readonly static AutoResetEvent _getDataResetEvent = new AutoResetEvent(true); private int GetData() { return 1; } public Task<int> GetPreviousDataAsync(out int cachedData) { // This will force calls to this method to be executed one by one, avoiding // N calls to his method update _cachedData class field in an unpredictable way // It will try to get a lock in 6 seconds. If it goes beyong 6 seconds it means that // the task is taking too much time. This will prevent a deadlock if (!_getDataResetEvent.WaitOne(TimeSpan.FromSeconds(6))) { throw new InvalidOperationException("Some previous operation is taking too much time"); } // It has acquired an exclusive lock since WaitOne returned true Task<int> getDataTask = Task.Run(() => GetData()); cachedData = _cachedData; // some previous value // Once the getDataTask has finished, this will set the // _cachedData class field. Since it an asynchronous // continuation, the return statement will be hit before the // task ends, letting the caller await for the asynchronous // operation, while the method was able to output // previous _cachedData using the "out" parameter. getDataTask.ContinueWith ( t => { if (t.IsCompleted) _cachedData = t.Result; // Open the door again to let other calls proceed _getDataResetEvent.Set(); } ); return getDataTask; } public void DoStuff() { int previousCachedData; // Don't await it, when the underlying task ends, sets // _cachedData already. This is like saying "fire and forget it" GetPreviousDataAsync(out previousCachedData); } } 
+7
source

You need to store the cached value in your class, and then when the value is requested, check if you are updating it. If you just return the cached value. If not, run a new query and return the cached value.

+1
source

If you do not need to wait for the task to complete, you can run this task and process it in ContinueWith

  public int GetPreviousData() { Task.Run((Func<int>)getData).ContinueWith(t => _cachedData = t.Result); return _cachedData; // some previous value } 

If race conditions are a problem, you can first assign _cachedData variable, then run the task and return the variable immediately, but if getData takes some time, this should not be a problem.

+1
source

Source: https://habr.com/ru/post/1237736/


All Articles