最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Flutter快學(xué)快用24講--03 事件循環(huán):Flutter 中代碼是如何執(zhí)行和運(yùn)行的

2023-03-15 13:28 作者:gzqhero  | 我要投稿

上節(jié)課介紹了 Dart 基礎(chǔ)數(shù)據(jù)類型、基礎(chǔ)運(yùn)算符、類以及庫與調(diào)用。本課時(shí)著重通過實(shí)踐帶你掌握 Dart 的運(yùn)行原理。

Dart 單線程

單線程在流暢性方面有一定安全保障,這點(diǎn)在 JavaScript 中存在類似的機(jī)制原理,其核心是分為主線程、微任務(wù)和宏任務(wù)。主線程執(zhí)行主業(yè)務(wù)邏輯,網(wǎng)絡(luò) I/O 、本地文件 I/O 、異步事件等相關(guān)任務(wù)事件,應(yīng)用事件驅(qū)動(dòng)方式來執(zhí)行。在 Dart 中同樣是單線程執(zhí)行,其次也包含了兩個(gè)事件隊(duì)列,一個(gè)是微任務(wù)事件隊(duì)列,一個(gè)是事件隊(duì)列。

  • 微任務(wù)隊(duì)列

微任務(wù)隊(duì)列包含有 Dart 內(nèi)部的微任務(wù),主要是通過 scheduleMicrotask 來調(diào)度。

  • 事件隊(duì)列

事件隊(duì)列包含外部事件,例如 I/O 、 Timer ,繪制事件等等。

事件循環(huán)

既然 Dart 包含了微任務(wù)和事件任務(wù),那么這兩個(gè)任務(wù)之間是如何進(jìn)行循環(huán)執(zhí)行的呢?我們可以先看下 Dart 執(zhí)行的邏輯過程(如圖 1):

  1. 首先是執(zhí)行 main 函數(shù),并生產(chǎn)兩個(gè)相應(yīng)的微任務(wù)和事件任務(wù)隊(duì)列;

  2. 判斷是否存在微任務(wù),有則執(zhí)行,執(zhí)行完成后再繼續(xù)判斷是否還存在微任務(wù),無則判斷是否存在事件任務(wù);

  3. 如果沒有可執(zhí)行的微任務(wù),則判斷是否存在事件任務(wù),有則執(zhí)行,無則繼續(xù)返回判斷是否還存在微任務(wù);

  4. 在微任務(wù)和事件任務(wù)執(zhí)行過程中,同樣會(huì)產(chǎn)生微任務(wù)和事件任務(wù),因此需要再次判斷是否需要插入微任務(wù)隊(duì)列和事件任務(wù)隊(duì)列。


Drawing 0.png

圖 1 Dart 事件循環(huán)機(jī)制

為了驗(yàn)證上面的運(yùn)行原理,我實(shí)現(xiàn)了下面的示例代碼,首先 import async 庫,然后在 main 函數(shù)中首先打印 flow start ,接下來執(zhí)行一個(gè)微任務(wù)事件,再執(zhí)行一個(gè)事件任務(wù),最后再打印 flow end 。

使用 Dart 運(yùn)行如上命令。

代碼的實(shí)際運(yùn)行過程如下:

  • 首先主線程邏輯,執(zhí)行打印 start ;

  • 執(zhí)行 Timer,為事件任務(wù),將其增加到事件任務(wù)隊(duì)列中;

  • 執(zhí)行 scheduleMicrotask,為微任務(wù)隊(duì)列,將其增加到微任務(wù)隊(duì)列中;

  • 執(zhí)行打印 flow end;

  • 判斷是否存在微任務(wù)隊(duì)列,存在則執(zhí)行微任務(wù)隊(duì)列,打印 mcrotask;

  • 判斷是否還存在微任務(wù)隊(duì)列,無則判斷是否存在事件任務(wù)隊(duì)列,存在執(zhí)行事件任務(wù)隊(duì)列,打印 event。

為了更清晰描述,可以我們使用圖 2 動(dòng)畫來演示。


flutter-flow-new.gif

圖 2 Dart 主線程運(yùn)行邏輯

介紹完 Dart 的運(yùn)行原理,你可能會(huì)產(chǎn)生以下疑問。

疑問1,為什么事件任務(wù)都執(zhí)行完成了,還需要繼續(xù)再循環(huán)判斷是否有微任務(wù)?

核心解釋是:微任務(wù)在執(zhí)行過程中,也會(huì)產(chǎn)生新的事件任務(wù),事件任務(wù)在執(zhí)行過程中也會(huì)產(chǎn)生新的微任務(wù)。產(chǎn)生的新微任務(wù),按照?qǐng)?zhí)行流程,需要根據(jù)隊(duì)列方式插入到任務(wù)隊(duì)列最后。

我們通過代碼來看下該過程。下面一段代碼, import async 庫,第一步打印 start , 然后執(zhí)行一個(gè)事件任務(wù),在事件任務(wù)中打印 event 。接下來增加了一個(gè)微任務(wù)事件,在微任務(wù)事件中打印 microtask in event 。第二步執(zhí)行微任務(wù)事件,在微任務(wù)事件中打印 microtask ,并且在其中增加事件任務(wù)隊(duì)列,事件任務(wù)隊(duì)列中打印 event in microtask ,最后再打印 flow end 。

使用 Dart 運(yùn)行如上命令。

代碼的實(shí)際運(yùn)行過程如下:

  • 首先還是依次執(zhí)行打印 flow start ;

  • 執(zhí)行 Timer 為事件任務(wù),添加事件任務(wù)隊(duì)列中;

  • 執(zhí)行 scheduleMicrotask 為微任務(wù),添加到微任務(wù)隊(duì)列中;

  • 打印 end ;

  • 執(zhí)行微任務(wù)隊(duì)列,打印 microtask ,其中包括了事件任務(wù),將事件任務(wù)插入到事件任務(wù)中;

  • 執(zhí)行事件任務(wù)隊(duì)列,打印 event ,其中包括了微任務(wù),將微任務(wù)插入到微任務(wù)隊(duì)列中;

  • 微任務(wù)隊(duì)列存在微任務(wù),執(zhí)行微任務(wù)隊(duì)列,打印 microtask in event;

  • 微任務(wù)隊(duì)列為空,存在事件任務(wù)隊(duì)列,執(zhí)行事件任務(wù)隊(duì)列,打印 event in microtask;

根據(jù)如上的運(yùn)行過程,我們可以得出以下的一個(gè)運(yùn)行結(jié)果,這點(diǎn)可以通過運(yùn)行 Dart 命令得到實(shí)際的驗(yàn)證。

為了更形象來描述,我使用圖 3 動(dòng)畫來演示。


image

圖 3 多微任務(wù)和事件任務(wù)執(zhí)行流程

一句話概括上面的實(shí)踐運(yùn)行結(jié)果:每次運(yùn)行完一個(gè)事件后,都會(huì)判斷微任務(wù)和事件任務(wù),在兩者都存在時(shí),優(yōu)先執(zhí)行完微任務(wù),只有微任務(wù)隊(duì)列沒有其他的任務(wù)了才會(huì)執(zhí)行事件任務(wù)。

疑問2,Dart 運(yùn)行過程中是否會(huì)被事件運(yùn)行卡???

答案是會(huì),比如在運(yùn)行某個(gè)微任務(wù),該微任務(wù)非常的耗時(shí),會(huì)導(dǎo)致其他微任務(wù)和事件任務(wù)卡住,從而影響到一些實(shí)際運(yùn)行,這里我們可以看如下例子:

上面這段代碼和之前的唯一不同點(diǎn)是在執(zhí)行第一個(gè)事件任務(wù)的時(shí)候,使用了一個(gè)大的 for 循環(huán),從運(yùn)行結(jié)果會(huì)看到 event in microtask 和 microtask in event 打印的時(shí)間會(huì)被 event 的執(zhí)行所 block 住。從結(jié)果分析來看 Dart 中事件運(yùn)行是會(huì)被卡住的,因此在日常編程的時(shí)候要特別注意,避免因?yàn)槟硞€(gè)事件任務(wù)密集計(jì)算,導(dǎo)致較差的用戶操作體驗(yàn)。

Isolate 多線程

上面我們介紹了 Dart 是單線程的,這里說的 Dart 的單線程,其實(shí)和操作系統(tǒng)的線程概念是存在一定區(qū)別的, Dart 的單線程叫作 isolate 線程, 每個(gè) isolate 線程之間是不共享內(nèi)存的,通過消息機(jī)制通信。

我們看個(gè)例子,例子是利用 Dart 的 isolate 實(shí)現(xiàn)多線程的方式。

使用 Dart 運(yùn)行如上命令。

以上代碼的執(zhí)行運(yùn)行流程如下:

  • import 對(duì)應(yīng)的庫;

  • 聲明兩個(gè)變量,一個(gè)是 isolate 對(duì)象,一個(gè)是字符串類型的 name;

  • 執(zhí)行 main 函數(shù),main 函數(shù)中執(zhí)行 isolateServer 異步函數(shù);

  • isolateServer 中創(chuàng)建了一個(gè) isolate 線程,創(chuàng)建線程時(shí)候,可以傳遞接受回調(diào)的函數(shù) changName;

  • 在 changName 中修改當(dāng)前的全局變量 name ,并且發(fā)送消息給到接收的端口,并且打印該線程中的 name 屬性;

  • isolateServer 接收消息,接收消息后打印返回的數(shù)據(jù)和當(dāng)前 name 變量。

根據(jù)如上執(zhí)行過程,可以得出如下的運(yùn)行結(jié)果。

從運(yùn)行結(jié)果中,可以看到新的線程修改了全局的 name,并且通過消息發(fā)送返回到主線程中。而主線程的 name 屬性并沒有因?yàn)閯?chuàng)建的新線程中的 name 屬性的修改而發(fā)生改變,這也印證了內(nèi)存隔離這點(diǎn)。

綜合示例

了解完以上知識(shí)點(diǎn)后,我再?gòu)囊粋€(gè)實(shí)際的例子進(jìn)行綜合的分析,讓你進(jìn)一步鞏固對(duì) Dart 運(yùn)行原理的掌握。

假設(shè)一個(gè)項(xiàng)目,需要 2 個(gè)團(tuán)隊(duì)去完成,團(tuán)隊(duì)中包含多項(xiàng)任務(wù)??梢苑譃?2 個(gè)高優(yōu)先級(jí)任務(wù)(高優(yōu)先級(jí)的其中,會(huì)產(chǎn)生 2 個(gè)任務(wù),一個(gè)是緊急一個(gè)是不緊急),和 2 個(gè)非高優(yōu)先級(jí)任務(wù)(非高優(yōu)先級(jí)的其中,會(huì)產(chǎn)生有 2 個(gè)任務(wù),一個(gè)是緊急一個(gè)是不緊急)。其中還有一個(gè)是必須依賴其他團(tuán)隊(duì)去做的,因?yàn)楸緢F(tuán)隊(duì)沒有那方面的資源,第三方也會(huì)產(chǎn)生一個(gè)高優(yōu)先級(jí)任務(wù)和一個(gè)低優(yōu)先級(jí)任務(wù)。

根據(jù)以上假設(shè),我們可以用表 1 任務(wù)劃分來表示:

主任務(wù)高優(yōu)先級(jí)任務(wù)(微任務(wù))低優(yōu)先級(jí)任務(wù)(事件任務(wù))第三方任務(wù)(isolate)H1h1-1l1-1否H2h2-1l2-1否L3h3-1l3-1否L4h4-1l4-1否C5ch5-1cl5-1是

表1 項(xiàng)目任務(wù)劃分詳情

然后我們按照 Dart 語言執(zhí)行方式去安排這個(gè)項(xiàng)目的開發(fā)工作,我們看看安排的工作到底會(huì)是怎么樣執(zhí)行流程,代碼實(shí)現(xiàn)方式如下。

使用 Dart 運(yùn)行如上命令。

我們先來看下,上面代碼的運(yùn)行結(jié)果。

H 和 L 的運(yùn)行原理,希望你用上面我所講到的知識(shí)點(diǎn),去一步步分析,可以像我們圖 2 或者圖 3 的方法,畫兩個(gè)隊(duì)列,然后逐步去分析。

上面的運(yùn)行結(jié)果中,非 C 任務(wù)的運(yùn)行原理留給你自己去分析,這里我著重介紹下為什么 C 的任務(wù)一直在最后才完成。

由于 C 任務(wù)是由其他線程執(zhí)行,因此這里存在一定的時(shí)間去創(chuàng)建線程。創(chuàng)建線程完成后,才會(huì)進(jìn)行回調(diào),回調(diào)后才會(huì)將相應(yīng)的回調(diào)事件插入到事件任務(wù)隊(duì)列中。因此 C1 task complete 會(huì)在最后的一個(gè)事件任務(wù)中執(zhí)行。而 ch5-1 task complete 和 cl5-1 task complete 由于需要等線程創(chuàng)建完成才能執(zhí)行,因此執(zhí)行也在后面。為了驗(yàn)證上面的結(jié)論,我們?cè)?ctask() 后面增加一段耗 CPU 計(jì)算的代碼,讓新的線程執(zhí)行快于當(dāng)前的主線程。

在運(yùn)行代碼后,你將看到這樣的結(jié)果:

首先就輸出了 C 線程中的微任務(wù)和事件任務(wù),C 任務(wù)完成后,向主線程的事件任務(wù)中插入事件任務(wù)。由于主線程還沒有運(yùn)行結(jié)束,接下來運(yùn)行后會(huì)產(chǎn)生微任務(wù)和事件任務(wù),由于 C 回調(diào)的事件任務(wù)最先插入,因此在事件任務(wù)中最先執(zhí)行,但是會(huì)慢于微任務(wù)事件的執(zhí)行。

總結(jié)

本課時(shí)首先介紹了 Dart 中單線程兩個(gè)概念微任務(wù)事件隊(duì)列和事件任務(wù)隊(duì)列,并通過實(shí)踐代碼運(yùn)行來介紹 Dart 事件循環(huán)方式。其次介紹了在 Dart 中應(yīng)用 isolate 實(shí)現(xiàn)多線程的方式。最后使用一個(gè)實(shí)際的例子,來練習(xí)掌握 Dart 運(yùn)行原理。在綜合例子里還涉及了多線程中微任務(wù)和事件任務(wù)的調(diào)度方式。

學(xué)完本課時(shí),你需要掌握其單線程中微任務(wù)隊(duì)列和事件任務(wù)隊(duì)列的調(diào)度方式,其次知道線程創(chuàng)建需要處理時(shí)間,以及線程事件執(zhí)行完成后的回調(diào)是一個(gè)事件任務(wù),這樣就可以掌握其整體的運(yùn)行原理了。如果你還有其他困惑,可以在下方留言或加入學(xué)習(xí)交流群。

以上就是本課時(shí)的主要內(nèi)容,下一課時(shí),我將用“三步法”帶你掌握 Flutter ,并開始你的第一個(gè)應(yīng)用,這也是我們即將開始實(shí)際的代碼編程的第一步。

點(diǎn)擊這里下載本課時(shí)源碼,F(xiàn)lutter 專欄,源碼地址: https://github.com/love-flutter/flutter-column

Flutter快學(xué)快用24講--03 事件循環(huán):Flutter 中代碼是如何執(zhí)行和運(yùn)行的的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
清水县| 古交市| 沙田区| 博兴县| 浠水县| 罗平县| 陈巴尔虎旗| 杂多县| 亳州市| 分宜县| 昭觉县| 汾西县| 朔州市| 阜城县| 奎屯市| 大城县| 西青区| 泾源县| 安国市| 威宁| 安泽县| 遂溪县| 朝阳区| 洛隆县| 长宁县| 博兴县| 子洲县| 化隆| 聂拉木县| 娄烦县| 卢氏县| 柳州市| 金坛市| 平遥县| 通渭县| 岫岩| 内丘县| 平潭县| 霍林郭勒市| 玉山县| 盐边县|