深刻了解Flutter的isolate(1) ---- 事件循環(event loop)及代碼運行順序

前言

接觸過Flutter的人都知道,Flutter是用Dart來寫的,Dart沒有進程和線程的概念,全部的Dart代碼都是在isolate上運行的,那麼isolate究竟是什麼?本系列的文章將詳細討論。這篇文章討論事件隊列(event loop)及Dart代碼運行順序。web

0x00 同步代碼和異步代碼

咱們對Dart代碼進行分類:同步代碼和異步代碼; 咱們在寫Dart代碼的時候,就只有兩種代碼,bash

  • 同步代碼:就是一行行寫下來的代碼
  • 異步代碼:就是以Future等修飾的代碼

這兩類代碼是不一樣的:架構

1.運行順序不一樣

同步代碼和異步代碼運行的順序是不一樣的:app

先運行同步代碼,在運行異步代碼
複製代碼

就是,即便我異步代碼寫在最前面,同步代碼寫在最後面,很差意思,我也是先運行後面的同步代碼,同步代碼都運行完後,在運行前面的異步代碼。異步

2.運行的機制不一樣

異步代碼是運行在event loop裏的,這是一個很重要的概念,這裏能夠理解成Android裏的Looper機制,是一個死循環,event loop不斷的從事件隊列裏取事件而後運行。async

0x01 event loop 架構

下面是event loop大體的運行圖: oop

這個很好理解,事件events加到Event queue裏,Event loop循環從Event queue裏取Event執行。

這個理解後,在看event loop詳細的運行圖: ui

從這裏看到,啓動app(start app)後:spa

  1. 先查看MicroTask queue是否是空的,不是的話,先運行microtask
  2. 一個microtask運行完後,會看有沒有下一個microtask,直到Microtask queue空了以後,纔會去運行Event queue 3.在Evnet queue取出一個event task運行完後,又會跑到第一步,去運行microtask

這裏多了兩個名詞:MicroTaskEvent,這表明了兩個不一樣的異步task線程

並且能夠看出:

  • 若是想讓任務可以儘快執行,就用MicroTask

1. MicroTask

這個你們應該不太清楚,可是這個也是dart:async提供的異步方法,使用方式:

// Adds a task to the 先查看MicroTask queue.
scheduleMicrotask((){
  // ...code goes here...
}); 
複製代碼

或者:

new Future.microtask((){
    // ...code goes here...
});
複製代碼

2.Event

Event咱們就很清楚了,就是Future修飾的異步方法,使用方式:

// Adds a task to the Event queue.
new Future(() {
  // ...code goes here...
});
複製代碼

0x02

純粹講理論知識不太好理解,咱們直接上代碼,講一個例子,看以下的代碼,請問打印順序是什麼樣的?

import 'dart:async';
void main() {
  print('main #1 of 2');
  scheduleMicrotask(() => print('microtask #1 of 3'));

  new Future.delayed(new Duration(seconds:1),
      () => print('future #1 (delayed)'));

  new Future(() => print('future #2 of 4'))
      .then((_) => print('future #2a'))
      .then((_) {
        print('future #2b');
        scheduleMicrotask(() => print('microtask #0 (from future #2b)'));
      })
      .then((_) => print('future #2c'));

  scheduleMicrotask(() => print('microtask #2 of 3'));

  new Future(() => print('future #3 of 4'))
      .then((_) => new Future(
                   () => print('future #3a (a new future)')))
      .then((_) => print('future #3b'));

  new Future(() => print('future #4 of 4'))
  .then((_){
    new Future(() => print('future #4a'));
  })
  .then((_) => print('future #4b'));
  scheduleMicrotask(() => print('microtask #3 of 3'));
  print('main #2 of 2');
}
複製代碼
  1. 首先運行同步代碼

    因此是:

    main #1 of 2
    main #2 of 2
    複製代碼
  2. 接下來是異步代碼

    Dart的Event Loop是先判斷 microtask queue裏有沒有task,有的話運行microtaskmicrotask運行完後,在運行event queue裏的event task,一個event task 運行完後,再去運行 microtask queue,而後在運行event queue

  3. microtask queue

    這裏就是:

    microtask #1 of 3
    microtask #2 of 3
    複製代碼
  4. event queue event queue還有有特殊的狀況須要考慮:

    • Future.delayed

      須要延遲執行的,Dart是怎麼執行的呢,是在延遲時間到了以後纔將此task加到event queue的隊尾,因此萬一前面有很耗時的任務,那麼你的延遲task不必定能準時運行

    • Future.then

      Future.then裏的task是不會加入到event queue裏的,而是當前面的Future執行完後當即掉起,因此你若是想保證異步task的執行順序必定要用then,不然Dart不保證task的執行順序

    • scheduleMicrotask

    一個event task運行完後,會先去查看Micro queue裏有沒有能夠執行的micro task。沒有的話,在執行下一個event task

    這裏就是:
    ```
    future #2 of 4
    future #2a
    future #2b
    future #2c
    microtask #0 (from future #2b)
    future #3 of 4
    future #4 of 4
    future #4b
    future #3a (a new future)
    future #3b
    future #4a
    future #1 (delayed)
    ```
    複製代碼

這裏你確定好奇爲啥future #3 of 4後面是future #4 of 4,而不是future #3a (a new future),由於 future #3 of 4的then裏又新建了一個Future:future #3a (a new future),因此future #3a (a new future)這個task會加到event queue的最後面。

最後的結果就是:

main #1 of 2
main #2 of 2
microtask #1 of 3
microtask #2 of 3
microtask #3 of 3
future #2 of 4
future #2a
future #2b
future #2c
microtask #0 (from future #2b)
future #3 of 4
future #4 of 4
future #4b
future #3a (a new future)
future #3b
future #4a
future #1 (delayed)
複製代碼

參考文章

webdev.dartlang.org/articles/pe…

相關文章
相關標籤/搜索