【问题标题】:How to use putIfAbsent for when action returns Future当操作返回 Future 时如何使用 putIfAbsent
【发布时间】:2018-07-15 04:34:32
【问题描述】:

在我的课堂上,我正在加载一些文件,为了提高效率,我想创建一个线程安全的缓存。我在地图类中看到有一个putIfAbsent 方法,但它不接受async 类型。也不确定这种结构是否可以安全使用。

这是我想要做的风格:

final Map<String, String> _cache = new Map();

Future<String> parse(final String name) async {
  _cache.putIfAbsent(name, () async { // this async is not allowed
    return await new File(name).readAsString();
  });
  return _cache[name];
}

因为我可以在参数上使用异步,所以我选择使用锁,但这会使代码更加冗长..

final Lock _lock = new Lock();
final Map<String, String> _cache = new Map();

Future<String> parse(final String name) async {
  if (!_cache.containsKey(name)) {
    await _lock.synchronized(() async {
      if (!_cache.containsKey(name)) {
        _cache[name] = await new File(name).readAsString();
      }
    });
  }

  return _cache[name];
}

有谁知道我可以如何简化这段代码,或者是否有更好的库可以用于线程安全缓存?

【问题讨论】:

    标签: dictionary caching concurrency dart thread-safety


    【解决方案1】:

    “不允许这种异步”是什么意思?我认为putIfAbsent 代码没有特别的问题,我相信它应该可以工作。 我看到的一个问题是缓存不是缓存期货,而是字符串。由于您的函数无论如何都会返回未来,因此您不妨将未来存储在缓存中。

    我会这样写:

    final Map<String, Future<String>> _cache = new Map();
    
    Future<String> parse(final String name) =>
        _cache.putIfAbsent(name, () => File(name).readAsString());
    

    但除了修复 _cache 映射类型之外,实际上是相同的,它只是避免创建和等待几个额外的未来。

    【讨论】:

    • 我的意思是,由于 putIfAbsent 的方法签名,不允许向 lambda 添加异步。缓存未来似乎是一个非常干净的解决方案!打算调查一下!
    【解决方案2】:

    我创建了一个扩展来支持 putIfAbsent 的异步操作:

    extension MapUtils<K, V> on Map<K, V> {
      Future<V> putIfAbsentAsync(K key, FutureOr<V> Function() action) async {
        final V? previous = this[key];
        final V current;
        if (previous == null) {
          current = await action();
          this[key] = current;
        } else {
          current = previous;
        }
        return current;
      }
    }
    

    你可以这样使用:

    final Map<String, String> _cache = {};
    
    Future<String> parse(final String name) async {
      return await _cache.putIfAbsentAsync(
        name,
        () async => await File(name).readAsString(),
        // ^^^^^ this `async` is now allowed
      );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多