Dart:如何在异步功能中管理并发 [英] Dart: how to manage concurrency in async function

查看:207
本文介绍了Dart:如何在异步功能中管理并发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很喜欢Dart中的async/await模式. 它使我能够编写可读的方法.

但是,有几件事是有问题的,尤其是其中一个,我根本不知道要处理什么.

问题在于,在方法内使用异步和多次等待,我们在方法中引入了并发性. 例如,如果我有一个方法:

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

嗯,这是一个非常简单的例子. 这里的问题是,每次等待时,该方法都会放入事件循环中. 可以理解,但是可以,但是这不会阻止您的应用程序重新调用该方法,因为它已经重新调整了一个值.

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

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

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方法会将其立即放入事件循环中,因此我认为该方法的并发调用的执行被延迟到第一个方法结束为止. 但事实并非如此,程序进入了一个无限循环.

任何人都可以给我一个解释和解决此问题的方法吗?

总的来说,与其他语言一样,我认为拥有一个同步关键字可能会很有趣,其含义是该方法(如果第二次调用)将等到第一个方法结束. 像这样:

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

我真的很兴奋,因为我认为我已经解决了很长时间的问题.感谢Argenti,尤其是Alexandre,这给了我解决方案.我只是简单地对解决方案进行了结构调整,以使其易于重用(至少对我而言),并将其发布在我创建的类上,并在此向有需要的人提供了示例(由您自己承担风险;-)). 我使用过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实例. 我希望它会有用.

解决方案

您可以使用Future https://dartpad.dartlang.org/dceafcb4e6349acf770b67c0e816e9a7 以便更好地了解工作流程. >

I really like the async/await pattern in Dart. It allows me to write readable methods.

But, there are a couple of things that are problematic, one in particular, I don't know hot to manage at all.

The problem is that with async and multiple await inside a method, we introduce concurrency in the method. For example If I have a method:

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

Well, this is a really simple example. The problem here is that, for every await, the method is put in the event loop. That is OK, when you understand it, but this does not prevent your application from calling again the method befor it has retuned a value.

Consider if the method is managing data that is common to the instance of the class and not to the method itself.

So, I have tried the following solution:

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;
}

As far as I have understood, calling a future method put it immediately in the event loop, so I thought that the execution of the concurrent call of the method was delayed until the first one was ended. But it is not like that, the program enters in an endless loop.

Anywone can give me an explanation and a solution to this question?

Edit: in general I think that it could be interesting to have, like in other languages, a synchronized keyword, with the meaning that the method, if called a second time will wait until the first has ended. Something like:

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

Edit 2:

I'm really excited because I think I got the solution for this problem that I had for a long time. Thanks to Argenti and in particular to Alexandre that give me the solution. I have simply restructured the solution for easy reuse (at least for me) and I post it here the class I have created and an example on how to use it for those who could need it (try at your own risk ;-) ). I have used a mixin because I find it practical, but you can use the Locker class alone if you like.

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;
  }
}

The class is:

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;
  }

}

I have structured the code this way so that you can use it easily in more than one method inside your classes. In this case you need a Locker instance per method. I hope that it can be useful.

解决方案

Instead of a boolean you can use a Future and a Completer to achieve what you want:

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;
}

The first time the method is call isWorking is null, doesn't enter the if section and create isWorking as a Future that will be complete at the end of the method. If an other call is done to foo before the first call has complete the Future isWorking, this call enter the if section and it waits for the Future isWorking to complete. This is the same for all calls that could be done before the completion of the first call. Once the first call has complete (and isWorking is set to null) the awaiting calls are notified they will call again foo. One of them will be entering foo as the first call and the same workflow will be done.

See https://dartpad.dartlang.org/dceafcb4e6349acf770b67c0e816e9a7 to better see the workflow.

这篇关于Dart:如何在异步功能中管理并发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆