introduction
Dart is a program that runs in a single thread. Execute an operation that takes a long time in the program. To avoid stuck in the main UI thread, we will use asynchronous (future), which allows the program to continue to process other work while waiting for a time-consuming operation to complete.
Before we get to the topic, let’s first understand the message loop mechanism of Dart:
- Dart executes tasks from two queues:Event event queueandMicrotask microtask queue
- The event loop will prioritize the microtask queue. Only after the microtask is cleared will the next item in the event event queue be dequeued and processed.
- Event queues have from Dart (Future, Timer, Isolate Message, etc.) and system (user input, I/O, etc.)
- The micro-task queue currently only contains Dart. Of course, we can also insert tasks into the micro-task ourselves.
What is Future
What is Future? Here we will briefly describe it in a short article. Future is an asynchronous execution that enables time-consuming functionality without blocking code.
main() { Future(() { print('I'm a time-consuming operation'); }).then((value){ print('future is over'); }); print('main'); }
//Print the result
main
I'm a time-consuming operation
The future is over
In the project, we useFuture
、Async
、await
Combining each other to achieve asynchronous encoding.
Does Future operations have 'atomicity'
As we have said in the above article, after the future is created, it will be directly added to the event queue and executed in sequence. So can the next future be executed before the previous future is completed without the identification?
The editor has written several examples to do experiments:
Experimental writing method one:
main() { Test1.future1().then((value) => print(value)); Test1.future2().then((value) => print(value)); } abstract class Test1 { static Future<String> future1() async { return Future(() async { print('Start future1'); await (1000000000); //Time-consuming operation print('A thousand years have passed'); return 'future1 is over'; }); } static Future<String> future2() async { return Future(() async { print('Start future2'); await (1000); //Time-consuming operation print('Continue future2'); return 'future2 is over'; }); } }
//Print the result
Start future1
A thousand years have passed
future1 is over
Start future2
Continue future2
Future2 is over
Experimental results:
- Judging from the print results,futureThe task is not interrupted, and the next one in the queue can be executed after the current task is executed.future
Experimental writing method two:
main() { Test2.future1().then((value) => print(value)); Test2.future2().then((value) => print(value)); } abstract class Test2 { static Future<String> future1() async { print('Start future1'); await (1000000000);//Time-consuming operation print('A thousand years have passed'); return 'future1 is over'; } static Future<String> future2() async { print('Start future2'); await (1000);//Time-consuming operation print('Continue future2'); return 'future2 is over'; } }
//Print results
Start future1
Start future2
A thousand years have passed
future1 is over
Continue future2
Future2 is over
Experimental results:
- future2existfuture1The mission started before it was finished.
- future2Will be herefuture1The response is completed after the task execution is completed, and the entire process still maintains the consistency between the order of completion and the order of joining the event queue.
Experimental writing method three:
main() { Test3.future1().then((value) => print(value)); Test3.future2().then((value) => print(value)); } abstract class Test3 { static Future<String> future1() async { print('Start future1'); await Future(() => (1000000000));//Time-consuming operation print('A thousand years have passed'); return 'future1 is over'; } static Future<String> future2() async { print('Start future2'); await (1000);//Time-consuming operation print('Continue future2'); return 'future2 is over'; } }
//Print results
Start future1
Start future2
Continue future2
Future2 is over
A thousand years have passed
future1 is over
Experimental results:
- Judging from the print results,future1After the start,future2Start the task directly, andfuture2After the task is completed, it is directly marked and completed.
- future1andfuture2The completion order has nothing to do with the order in which the event queue is added, and is only positively correlated with internal time consumption.
Attached with time-consuming code:
abstract class TestTool { ///Time-consuming operation static Future<int> timeConsume(int num) async { final result = _timeConsume(num); return result; } static int _timeConsume(int num) { int count = 0; while (num > 0) { if (num % 2 == 0) { count++; } num--; } return count; } }
Conclusion of argument
Comprehensive analysis of the above three writing methods:
Inside the future method bodyNot a reliable 'atomic operation', Different writing methods have different differences. If you want to use the entire method body as an undetachable execution unit. Use Future to wrap the package on the outer layer, as in the Test1 example in Writing Method 1:
static Future<T> funcName() async { return Future(() async { ... Specific method content ... return result; }); }
The future will be added to the event event queue at the same time as it is created. Event queues are executed sequentially, but the order of completion of each future is the order of joining.No reliable consistency. If you want to maintain consistency in the order within the business, you can refer to the above writing method or useawait
Forced waiting such as:
main() async { await Test2.future1().then((value) => print(value)); Test2.future2().then((value) => print(value)); }
Write this way, future2 will not enter the starting state after future1 is executed.
The above is the detailed content of the addition of multiple future queues of Dart to the order relationship and atomicity argument. For more information about the atomicity of multiple futures of Dart, please pay attention to my other related articles!