如何在任务执行时缓存数据
本文关键字:缓存 数据 执行 任务 | 更新日期: 2023-09-27 18:27:56
private Data GetDefaultData()
{
var data = Task.Factory.StartNew(() => GetData());
return data.Result;
}
如果GetData()
在 100 毫秒内执行,而我每 10 毫秒运行一次GetDefaultData()
。前 10 个调用将使用相同的data.Result
是否正确? GetData()
lock
语句中收集Data
。如果不是,如何更改代码以提供此机会?
假设,我们有第一次调用 GetDefaultData(GetData(( 在 100ms 内执行(,然后我们有 10 次调用(GetDefaultData(( 每 10ms (。我希望其余的电话将得到与第一个相同的答案。
听起来你想要Lazy<T>
类。
public class YourClass
{
private readonly Lazy<Data> _lazyData;
public YourClass()
{
_lazyData = new Lazy<Data>(() => GetData());
}
private Data GetDefaultData()
{
return _lazyData.Value;
}
public Data GetData()
{
//...
}
}
第一个调用GetDefaultData()
的线程将在GetData()
_lazyData.Value
运行时运行,其余所有线程将在调用_lazyData.Value
阻塞,直到第一个线程完成并使用第一个线程调用的结果。 GetData()
只会被调用一次。
如果您不希望调用被阻止,则可以轻松地创建一个在内部使用 Threads 的AsyncLazy<T>
类。
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{
}
public AsyncLazy(Func<Task<T>> taskFactory, bool runFactoryInNewTask = true) :
base(() => runFactoryInNewTask ? Task.Run(taskFactory) : taskFactory())
{
}
//This lets you use `await _lazyData` instead of doing `await _lazyData.Value`
public TaskAwaiter<T> GetAwaiter()
{
return Value.GetAwaiter();
}
}
然后你的代码变成了(我也使 GetData 成为一个异步函数,但AsyncLazy
的重载让它成为 or (
public class YourClass
{
private readonly AsyncLazy<Data> _lazyData;
public YourClass()
{
_lazyData = new AsyncLazy<Data>(() => GetData(), false);
}
private async Task<Data> GetDefaultData()
{
//I await here to defer any exceptions till the returned task is awaited.
return await _lazyData;
}
public Task<Data> GetData()
{
//...
}
}
编辑:AsyncLazy可能存在一些问题,请参阅此处。
简而言之:不。
每次调用 GetDefaultData(( 时,都会启动一个新任务,因此 Data.Result 将在 GetData(( 期间保持不变,然后包含您在 GetData(( 中分配给它的内容。此外,从新的 Task 对象返回值对您没有好处 - 这就是多任务处理的工作方式。您的代码将继续在主线程中执行,但只有在单独的任务完成执行后才会设置结果值。它是否包含锁定语句。
可能 ReaderWriterLock 适合您。ReaderWriterLock 用于同步对资源的访问。在任何给定时间,它都允许对多个线程进行并发读取访问,或对单个线程进行写入访问。此逻辑可能应该嵌入到 GetData 方法中,以便在某个超时时,它可以使用写锁定并在此超时时间内保留它,否则使用读取操作。