简体   繁体   English

如何从Task返回结果?

[英]How to return the result from 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 don't want to wait for the result of an already running operation. 我不想等待已经运行的操作的结果。

I want to return _cachedData and update it after the Task will finish. 我想返回_cachedData并在Task完成后_cachedData进行更新。

How to do this? 这该怎么做? I'm using .net framework 4.5.2 我正在使用.net framework 4.5.2

You might want to use an out parameter here: 您可能要在此处使用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);

Pay attention to the Task.Run thing: this starts a task using the thread pool and returns a Task<int> to let the caller decide if it should be awaited, continued or fire and forget it. 请注意Task.Run事情:这将使用线程池启动任务,并返回Task<int>以使调用方决定应等待,继续还是执行并忘记它。

See the following sample. 请参阅以下示例。 I've re-arranged 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'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);
    }
}

You need to store the cached value in your class, and then when the value is queried check whether you're already updating it. 您需要将缓存的值存储在您的类中,然后在查询该值时检查是否已在更新它。 If you are just return the cached value. 如果只是返回缓存的值。 If not then launch a new query and return the cached value. 如果不是,则启动新查询并返回缓存的值。

If you don't have to wait at all for the task to finish, you can have the function start the task and handle the setting in a ContinueWith 如果您完全不必等待任务完成,则可以让该函数启动任务并在ContinueWith处理设置。

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

If race conditions are an issue, you can assign _cachedData to a variable first, then run the task and immediately return the variable, but if getData takes any time at all, that shouldn't be an issue. 如果出现竞争条件,则可以_cachedData分配给变量,然后运行任务并立即返回该变量,但是如果getData花费任何时间,那不应该成为问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM