[英]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.