如何从Task返回结果

本文关键字:返回 结果 Task | 更新日期: 2023-09-27 18:26:11

我有以下方法:

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

如何从Task返回结果

您可能需要在此处使用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);
    }
}

您需要将缓存的值存储在类中,然后在查询该值时检查您是否已经在更新它。如果您只是返回缓存的值。如果没有,则启动一个新查询并返回缓存的值。

如果你根本不需要等待任务完成,你可以让函数启动任务并在ContinueWith 中处理设置

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

如果竞争条件是一个问题,可以先将_cachedData分配给变量,然后运行任务并立即返回变量,但如果getData需要任何时间,那就不应该是问题。