Principle analysis of fluent async and await

I async await and Future

There are three keywords in asynchronous call, async, await and Future. Async and await need to be used together. In Dart, asynchronous operations can be performed through async and await. Async means to start an asynchronous operation or return a Future result. If there is no return value, a Future with null return value will be returned by default.

The operation of await will not affect the execution of subsequent code outside the method; Only subsequent code of async method will be blocked

Example 1

_testAsyncKeyword() {
    print("test The function starts: ${DateTime.now()}");
    _testString().then((value) => print(value));
    print("test The function ends: ${DateTime.now()}");
  }

  Future<String> _testString() async {
    Future f = Future.delayed(Duration(milliseconds: 300), () {
      return "I'm a test string===1";
    });
    String result = await f;
    print("I'm a test string===2");
    return result;
  }
// Fluent: test function started: 2021-05-27 13:58:56.5964
// Fluent: test function ended: 2021-05-27 13:58:56.598801
// Fluent: I'm the test string = = = 2
// Fluent: I'm the test string = = = 1

In the example code, execute to_ The teststring () method will be synchronized into the method for execution. When it is executed to await, it will stop the internal execution of async and continue to execute the external code. Therefore, the operation of await will not affect the execution of the following code ("the end of the test function" will precede the internal printing of _testString()).
When await returns, it will continue to execute from the position of await (so first print out "I am test string = = = 2", then return the result of Future, and print out "I am test string = = = 1").

Example 2

_testAsyncKeyword() async {
    print("test The function starts: ${DateTime.now()}");
    print(await _testString());
    print("test The function ends: ${DateTime.now()}");
  }

  Future<String> _testString() async {
    Future f = Future.delayed(Duration(milliseconds: 300), () {
      return "I'm a test string===1";
    });
    String result = await f;
    print("I'm a test string===2");
    return result;
  }

// Fluent: test function started: 2021-05-27 14:06:48.185704
// Fluent: I'm the test string = = = 2
// Fluent: I'm the test string = = = 1
// Fluent: test function ends: 2021-05-27 14:06:48.497481

In the code example_ Testasynckeyword () itself has an await operation, which will stop when await is executed_ testAsyncKeyword() the internal execution of async Wait_ After the result of testString() is returned, continue to execute

_ There is also an await operation inside testString(), which will stop when await is executed_ testString() async internal execution, wait for 300 milliseconds, and print string 2 after Future results

_ testAsyncKeyword() continues printing string 1 and ends

Example 3

_testAsyncKeyword() {
    print("test The function starts: ${DateTime.now()}");
    firstString().then((value) => print(value));
    secondString().then((value) => print(value));
    thirdString().then((value) => print(value));
    print("test The function ends: ${DateTime.now()}");
  }

_testKeyword2() async{
    print("test The function starts: ${DateTime.now()}");
    print(await firstString());
    print(await secondString());
    print(await thirdString());
    print("test The function ends: ${DateTime.now()}");
  }
Future<String> firstString() {
    return Future.delayed(Duration(milliseconds: 300), () {
      return "I am a string";
    });
  }

  Future<String> secondString() {
    return Future.delayed(Duration(milliseconds: 200), () {
      return "I'm a second string";
    });
  }

  Future<String> thirdString() {
    return Future.delayed(Duration(milliseconds: 100), () {
      return "I'm three strings";
    });
  }

//_ Printing of testAsyncKeyword():
//Fluent: test function started: 2021-05-27 14:17:42.620409
//Fluent: test function ends: 2021-05-27 14:17:42.624359
//Fluent: I'm three strings
//Flitter: I'm two strings
//Fluent: I'm a string

//_ Printing of testKeyword2():
//Fluent: test function started: 2021-05-27 14:18:41.401992
//Fluent: I'm a string
//Flitter: I'm two strings
//Fluent: I'm three strings
//Fluent: test function ends: 2021-05-27 14:18:42.027575

Through the above three examples, you can see the difference and relationship between await async and then

II The principle of async and await

async and await operations are "pseudo asynchronous". Why?
If we want to get the answer to this question, first of all, we need to understand the principles of async and await and the concept of synergy, because async and await are essentially a kind of syntax sugar of synergy. Coroutine, also known as coroutine, is a smaller unit than thread. In terms of unit size, it can be basically understood as "process - > thread - > co process".

1. Task scheduling

Before understanding the cooperative process, we must first understand the concepts of concurrency and parallelism

  • Concurrency: it refers to that the system manages the switching of multiple IO S and sends them to the CPU for processing.
  • Parallel: refers to the multi-core CPU executing multiple tasks at the same time.

Concurrency is realized by non blocking operation + event notification, which is also called "interrupt". The operation process is divided into two types. One is that the CPU operates the IO and initiates an interrupt after the operation is completed to tell the IO that the operation is completed. The other is that IO initiates an interrupt to tell the CPU that it can operate.

Thread: in essence, it also depends on interrupts for scheduling. Another kind of thread is called "blocking interrupt", which is to block the thread during IO operation and wait for the execution to be completed before continuing. A large number of concurrent operations can be carried out through single thread concurrency. However, the consumption of threads is very large, which is not suitable for the processing of a large number of concurrent operations, and a single thread can only use a single CPU. When multi-core CPU appears, a single thread cannot make good use of the advantages of multi-core CPU, so the concept of thread pool is introduced to manage a large number of threads through thread pool. When we need to execute multiple tasks at the same time, we will use multithreading to execute concurrently

Single thread concurrency 7. Single thread concurrency - brief book

Dart single thread operation model: input single absorption into operation mechanism, which mainly realizes task scheduling and processing through message circulation mechanism

2. coroutine

About co process https://zhuanlan.zhihu.com/p/172471249
When a multithreaded concurrent operating system waits for IO, it will block the current thread and switch to other threads, so that other threads can continue to execute while the current thread waits for Io. There is no problem when there are few threads in the system, but there is a problem when the number of threads is very large. First, the system thread will occupy a lot of memory space. Second, too many thread switching will occupy a lot of system time.
The collaboration {runs on the thread. After the execution of one collaboration is completed, you can choose to actively give up and let another collaboration run on the current thread. The number of threads is not increased, but multiple processes are run by time-sharing reuse on the basis of threads. Moreover, the switching of processes is completed in user mode, and the cost of switching is much lower than that of threads from user mode to kernel mode.

Cooperative process is divided into wireless cooperative process and wired cooperative process

  • When leaving the current call location, the wireless coopera will put the current variable in the heap area, and when it returns to the current location, it will continue to get the variables from the heap area. Therefore, when executing the current function, the variables will be directly allocated to the heap area, and async and await belong to a kind of wireless co process.
  • The wired coroutine will continue to save the variable in the} stack area, and will continue to take out the call from the stack when it returns to the leaving position pointed by the pointer.

3.async and await principles

The reason why async/await is pseudo asynchronous is that it does not start a new thread during execution, let alone concurrent execution, but is realized through task scheduling on a single thread (collaborative process, no concurrent execution function):
When the code is executed to async, it means entering a collaborative process, and the code blocks of async will be executed synchronously. Async's code block is essentially a function and has its own context. When await is executed, it indicates that there is a task to wait, and the CPU schedules the execution of other IO, that is, the following code or other co process code. After a period of time, the CPU will poll once to see whether a certain process has been processed and whether the returned results can be continued. If it can be continued, it will continue to execute along the position pointed by the pointer when it left last time, that is, the position of the await flag.

Since no new thread is started, only IO interrupt is performed to change CPU scheduling, async and await can be used for asynchronous operations such as network requests, but if a large number of time-consuming synchronous operations are performed, isolate should be used to open up new threads for execution.

Keywords: Java Android Flutter

Added by Fawkman on Mon, 21 Feb 2022 09:17:00 +0200