I really like the async / await template in Dart. This allows me to write readable methods.
But there are a few things that are problematic, in particular, I donβt know how to manage at all.
The problem is that with asynchronous and multiple waiting inside the 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 each wait, the method is placed in an event loop. This is normal when you understand this, but that does not stop your application from invoking the method again before it reconfigures the value.
Consider whether a method manages data that is common to an instance of a class, and not to the method itself.
So, I 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 I understand it, a call to a future method immediately put it in an event loop, so I thought that doing a parallel call to the method was delayed until its first completion. But this is not so, the program enters an endless cycle.
Can anyone give me an explanation and solution to this issue?
Edit: In general, I think it would 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 one ends. Sort of:
Future<int> foo(int value) async synchronized {
Edit 2:
I am very excited because I think that I have a solution to this problem that I have had for a long time. Thanks to Argenti and, in particular, to Alexander, who give me the solution. I just reorganized the solution for easy reuse (at least for me) and I post it here in the class I created and an example on how to use it for those who need it (try at your own risk and risk ;-)). I used mixin because I find it practical, but you can use the Locker class if you want.
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; } }
Grade:
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 structured the code so that you can easily use it in several methods inside your classes. In this case, you need a Locker instance for each method. I hope this can be helpful.