我很喜欢Dart中的异步/等待模式.

但是,有几件事是有问题的,特别是有一件事,我根本不知道该如何处理.

问题是,在一个方法中使用异步和多重等待时,我们在该方法中引入了并发性.

Future<int> foo(int value) async {
await foo2();
await foo3();
await foo4();
int ret = foo5(value);
return ret;
}

这是一个非常简单的例子.

请考虑该方法是否管理对类实例而不是方法本身所共有的数据.

因此,我try 了以下解决方案:

bool isWorking = false;

Future<int> foo(int value) async {
if (isWorking) return foo(value);
isWorking = true;

await foo2();
await foo3();
await foo4();
int ret = foo5(value);

isWorking = False;

return ret;
}

据我所知,调用将来的方法会将其立即放入事件循环中,所以我认为该方法的并发调用的执行会延迟到第一个调用结束. 但事实并非如此,程序进入了一个无穷无尽的循环.

有人能给我一个解释和解决这个问题的方法吗?

编辑: 总的来说,我认为像在其他语言中一样,拥有一个同步关键字可能很有趣,意思是如果第二次调用该方法,它将等到第一次调用结束. 类似于:

Future<int> foo(int value) async synchronized {

编辑2:

我真的很兴奋,因为我想我已经解决了这个问题很长一段时间了.感谢阿根廷,特别是亚历山大,他们给了我解决方案.为了便于重用(至少对我来说是这样),我简单地重新构建了解决方案,并在此发布了我创建的类和一个示例,说明如何为那些可能需要它的人使用它(try 风险自负;-). 我使用了Mixin,因为我发现它很实用,但是如果您愿意,您可以单独使用Locker类.

myClass extends Object with LockManager {

  Locker locker = LockManager.getLocker();

  Future<int> foo(int value) async {

   _recall() {
      return foo(value);
   } 

   if (locker.locked) {
     return await locker.waitLock();
   }
   locker.setFunction(_recall);
   locker.lock();

   await foo2();
   await foo3();
   await foo4();
   int ret = foo5(value);

   locker.unlock();

   return ret;
  }
}

课程是:

import 'dart:async';

class LockManager {

static Locker getLocker() => new Locker();

}

class Locker {

  Future<Null> _isWorking = null;
  Completer<Null> completer;
  Function _function;
  bool get locked => _isWorking != null;

  lock() {
    completer = new Completer();
    _isWorking = completer.future;
  }

  unlock() {
    completer.complete();
    _isWorking = null;
  }

  waitLock() async {
      await _isWorking;
      return _function();
  }

  setFunction(Function fun) {
    if (_function == null) _function = fun;
  }

}

我以这种方式组织了代码,以便您可以在类中的多个方法中轻松使用它.在这种情况下,每个方法都需要一个Locker实例. 我希望它能有所帮助.

推荐答案

您可以使用FutureCompleter来代替布尔值来实现您想要的结果:

Future<Null> isWorking = null;

Future<int> foo(int value) async {
  if (isWorking != null) {
    await isWorking; // wait for future complete
    return foo(value);
  }

  // lock
  var completer = new Completer<Null>();
  isWorking = completer.future;

  await foo2();
  await foo3();
  await foo4();
  int ret = foo5(value);

  // unlock
  completer.complete();
  isWorking = null;

  return ret;
}

方法第一次调用isWorkingnull,不会进入if部分并创建isWorking作为将来,这将在方法结束时完成.如果在第一个呼叫完成future isWorking之前对foo进行了另一个呼叫,则此呼叫进入if部分,并等待future isWorking完成.对于在第一个呼叫完成之前可以完成的所有呼叫,这是相同的.一旦第一次呼叫已经完成(并且isWorking被设置为null),等待的呼叫被通知它们将再次呼叫foo.其中一个将作为第一个呼叫进入foo,并且将执行相同的工作流.

请参见https://dartpad.dartlang.org/dceafcb4e6349acf770b67c0e816e9a7以更好地查看工作流.

Dart相关问答推荐

聆听Firestore计数()

程序给出不准确的值

如何防止 getter 或函数每次都重新计算?

`异步内联方法`的这些定义之间有什么区别?

FlutterError (setState() 在 dispose() 之后调用:(生命周期状态:defunct,not mounted)

SliverList / SliverChildBuilderDelegate 提供初始索引或允许负索引

如何计算列表中元素的出现次数

不要将 PageView 居中 - Flutter

无法将小部件标记为需要构建,因为框架已经在构建小部件的过程中

Flutter:如何检测键盘按键?

如何在命令行上创建和运行Dart元素

将Dart嵌入到应用程序中

dart的Completer和Future?

有没有更好的方法来找出文件或目录是否存在?

在我的 angular-cli 元素中从 node-sass 切换到 dart sass

Dart,对泛型的限制?

方法级联如何在 dart 中准确工作?

Dart 中的外部是什么意思?

如何在 Dart 中创建私有变量?

如何比较 Dart 中的列表是否相等?