2015-12-09 4 views
5

У меня есть следующие методы:Как вернуть результат из задачи?

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 
} 

я не хочу ждать результата уже запущенной операции.

Я хочу вернуть _cachedData и обновить его после завершения Task.

Как это сделать? Я использую .net framework 4.5.2

ответ

7

Вы можете использовать out параметр здесь:

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); 

Обратите внимание на Task.Run вещь: это запускает задачу, используя пул потоков и возвращает Task<int>, чтобы звонящий решить если его следует ожидать, продолжение или огонь и забыть это.

См. Следующий образец. Я перестроены все в классе:

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's 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); 
    } 
} 
+0

Мне нужно вернуть предыдущие кэшированные данные, но вы вернете «Задачу». –

+0

@ivan_petrushenko вам нужно изучить Task Asynchronous Pattern. Посмотрите в сети информацию об этой концепции. BTW, проверьте мой обновленный ответ. –

+0

@ivan_petrushenko Я считаю, что мой ответ - хорошее начало для вас, чтобы обновить свои знания и навыки .NET. Почему бы вам не потратить время, чтобы понять, что такое 'Задача', что такое асинхронный ожидания, параметр' out'? Это только мой совет. –

1

Вы должны хранить кэшированные значения в классе, а затем, когда значение запрашивается проверка ли вы уже его обновления. Если вы просто вернете кешированное значение. Если нет, запустите новый запрос и верните кешированное значение.

+0

Можете ли вы представить код своей идеи? –

1

Если вы не должны ждать вообще для задачи, чтобы закончить, вы можете иметь функцию запуска задачи и обрабатывать установку в ContinueWith

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

Если условия гонки являются проблемой, вы может сначала назначить _cachedData переменной, затем запустить задачу и немедленно вернуть переменную, но если getData занимает какое-то время, это не должно быть проблемой.

+1

Зачем использовать явные продолжения, когда мы 'async' -'await' –

+0

Я использую .net framework 4.5.2 –

+0

@ivan_petrushenko вы застряли в .net 3.5 в своем уме: D Что должно делать .NET 4.5 .2 с этим ответом? TAP/TPL доступен с .NET 4.0 (2009?) –

Смежные вопросы