如何在任务执行时缓存数据

本文关键字:缓存 数据 执行 任务 | 更新日期: 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 方法中,以便在某个超时时,它可以使用写锁定并在此超时时间内保留它,否则使用读取操作。