欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter?異步編程之單線程下異步模型圖文示例詳解

 更新時(shí)間:2022年09月19日 08:54:51   作者:張風(fēng)捷特烈  
這篇文章主要為大家介紹了Flutter?異步編程之單線程下異步模型圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、 本專(zhuān)欄圖示概念規(guī)范

本專(zhuān)欄是對(duì) 異步編程 的系統(tǒng)探索,會(huì)通過(guò)各個(gè)方面去認(rèn)知、思考 異步編程 的概念。期間會(huì)用到一些圖片進(jìn)行表達(dá)與示意,在一開(kāi)始先對(duì)圖中的元素和 基本概念 進(jìn)行規(guī)范和說(shuō)明。

1. 任務(wù)概念規(guī)范

任務(wù) : 完成一項(xiàng)需求的基本單位。

分發(fā)任務(wù): 觸發(fā)任務(wù)開(kāi)始的動(dòng)作。

任務(wù)結(jié)束: 任務(wù)完成的標(biāo)識(shí)。

任務(wù)生命期: 任務(wù)從開(kāi)始到完成的時(shí)間跨度。

如下所示,方塊 表示任務(wù);當(dāng) 箭頭指向一個(gè)任務(wù)時(shí),表示對(duì)該任務(wù)進(jìn)行分發(fā);任何被分發(fā)的任務(wù)都會(huì)結(jié)束。在任務(wù)分發(fā)和結(jié)束之間,有一條虛線進(jìn)行連接,表示 任務(wù)生命期 。

2. 任務(wù)的狀態(tài)

未完成 : Uncompleted
成功完成 : Completed with Success
異常結(jié)束 : Completed with Error

一個(gè)任務(wù)生命期間有三種狀態(tài),如下通過(guò)三種顏色表示。在 任務(wù)結(jié)束 之前,該任務(wù)都是 未完成 態(tài),通過(guò) 淺藍(lán)色 表示;任何被分發(fā)的任務(wù)都是為了完成某項(xiàng)需求,任何任務(wù)都會(huì)結(jié)束,在結(jié)束時(shí)刻根據(jù)是否完成需求,可分為 成功完成 和 異常結(jié)束 兩種狀態(tài),如下分別用 綠色 和 紅色 表示。

3. 時(shí)刻與時(shí)間線

機(jī)體 : 任務(wù)分發(fā)者或處理者。
時(shí)刻: 機(jī)體運(yùn)行中的某一瞬間。
時(shí)間線: 所有時(shí)刻構(gòu)成的連續(xù)有向軸線。

在一個(gè)機(jī)體運(yùn)行的過(guò)程中,時(shí)間線是絕對(duì)的,通過(guò) 紫色有向線段 表示時(shí)間的流逝的方向。時(shí)刻 是時(shí)間線上任意一點(diǎn) ,通過(guò) 黑點(diǎn) 表示。

4.同步與異步

同步 : 機(jī)體在時(shí)間線上,將任務(wù)按順序依次分發(fā)。

同步執(zhí)行任務(wù)時(shí),前一個(gè)任務(wù)完成后,才會(huì)分發(fā)下一任務(wù)。意思是說(shuō): 任意時(shí)刻只有一個(gè)任務(wù)在生命期中。

異步: 機(jī)體在時(shí)間線上,在一個(gè)任務(wù)未完成時(shí),分發(fā)另一任務(wù)。

也就是說(shuō)通過(guò)異步編程,允許某時(shí)刻有兩個(gè)及以上的任務(wù)在生命期中。如下所示,在 任務(wù)1 完成后,分發(fā) 任務(wù)2; 在 任務(wù)2 未結(jié)束的情況下,可以分發(fā) 任務(wù) 3 。此時(shí)對(duì)于任務(wù) 3 來(lái)說(shuō),任務(wù) 2 就是異步執(zhí)行的。

二、理解單線程中的異步任務(wù)

上面對(duì)基本概念進(jìn)行了規(guī)范,看起來(lái)可能比較抽象,下面我們通過(guò)一個(gè)小場(chǎng)景來(lái)理解一下。媽媽早上出門(mén)散步,臨走前囑咐:

小捷,別睡了??炱鸫玻驯蛔訒褚幌?,地掃一下。還有,沒(méi)開(kāi)水了,記得燒。

當(dāng)前場(chǎng)景下只有小捷 一個(gè)機(jī)體,需要完成的任務(wù)有四個(gè):起床、曬被、拖地 、燒水 。

1. 任務(wù)的分配

當(dāng)機(jī)體有多個(gè)任務(wù)需要分發(fā)時(shí),需要對(duì)任務(wù)進(jìn)行分配。認(rèn)識(shí)任務(wù)之間的關(guān)系,是任務(wù)分配的第一步。只有理清關(guān)系,才能合理分配任務(wù)。分配過(guò)程中需要注意:

[1] 任務(wù)之間可能存在明確的先后順序,比如起床 需要在 曬被 之前。
[2] 任務(wù)之間先后順序也可能無(wú)所謂,比如先掃地還是先曬被,并沒(méi)有太大區(qū)別。
[3] 某類(lèi)任務(wù)只需要機(jī)體來(lái)分發(fā),生命期中不需要機(jī)體處理,并且和后續(xù)的任務(wù)沒(méi)有什么關(guān)聯(lián)性,比如燒水任務(wù)。

像燒水這種任務(wù),即耗時(shí),又不需要機(jī)體在任務(wù)生命期中做什么事。如果這類(lèi)任務(wù)使用同步處理,那么任務(wù)期間機(jī)體能做的事只有 等待 。對(duì)于一個(gè)機(jī)體來(lái)說(shuō),這種等待就會(huì)意味著阻塞,不能處理任何事。

結(jié)合日常生活,我們知道當(dāng)前場(chǎng)景之中,想要發(fā)揮機(jī)體最大的效力,最好的方式是起床之后,先分發(fā) 燒水任務(wù),不需要等待燒水任務(wù)完成,就去執(zhí)行曬被、掃地任務(wù)。這樣的任務(wù)分配就是將 燒水 作為一個(gè)異步任務(wù)來(lái)執(zhí)行的。

但在如果在分配時(shí),將燒水作為最后一個(gè)任務(wù),那么異步執(zhí)行的價(jià)值就會(huì)消失。所以對(duì)任務(wù)的合理分配,對(duì)機(jī)體的處理效率是非常重要的。

2.異步任務(wù)特點(diǎn)

從上面可以看出,異步任務(wù) 有很明顯的特征,并不是任何任務(wù)都有必要異步執(zhí)行。特別是對(duì)于單一機(jī)體來(lái)說(shuō),任務(wù)生命期間需要機(jī)體親自參與,是無(wú)法異步處理的。 比如一個(gè)人不能一邊曬被 ,一邊 掃地 。所以對(duì)于單線程來(lái)說(shuō),像一些只需要 分發(fā)任務(wù),任務(wù)的具體執(zhí)行邏輯由其他機(jī)體完成的任務(wù),適合使用 異步 處理,來(lái)避免不必要的等待。

這種任務(wù),在應(yīng)用程序中最常見(jiàn)的是網(wǎng)絡(luò) io和 磁盤(pán) io 的任務(wù)。比如,從一個(gè)網(wǎng)絡(luò)接口中獲取數(shù)據(jù),對(duì)于機(jī)體來(lái)說(shuō),只需要分發(fā)任務(wù)來(lái)發(fā)送請(qǐng)求,就像燒水時(shí)只需要裝水按下啟動(dòng)鍵一樣。而服務(wù)器如何根據(jù)請(qǐng)求,查詢數(shù)據(jù)庫(kù)來(lái)返回響應(yīng)信息,數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸?shù)?,和分發(fā)任務(wù)的機(jī)體沒(méi)有關(guān)系。磁盤(pán)的訪問(wèn)也是一樣,分發(fā)讀寫(xiě)文件任務(wù)后,真正干活的是操作系統(tǒng)。

像這類(lèi)任務(wù)通過(guò)異步處理,可以避免在分發(fā)任務(wù)后,機(jī)體因等待任務(wù)的結(jié)束而阻塞。在等待其他機(jī)體處理的過(guò)程中,去分發(fā)其他任務(wù),可以更好地分配時(shí)間。比如下面所示,網(wǎng)絡(luò)數(shù)據(jù)獲取 的任務(wù)分發(fā)后,需要通過(guò)網(wǎng)絡(luò)把請(qǐng)求傳輸給服務(wù)器,服務(wù)器進(jìn)行處理,給出響應(yīng)結(jié)果。

整個(gè)任務(wù)處理的過(guò)程,并不需要機(jī)體參與,所以分發(fā) 網(wǎng)絡(luò)數(shù)據(jù)獲取 任務(wù)后,無(wú)需等待任務(wù)完成,接著分發(fā) 構(gòu)建加載中界面 的任務(wù),來(lái)展示加載中的界面。從而給出用戶交互的反饋,而不是阻塞在那里等待網(wǎng)絡(luò)任務(wù)完成,這就是一個(gè)非常典型的異步任務(wù)使用場(chǎng)景。

3. 異步任務(wù)完成與回調(diào)

前面的介紹中可以看出,異步任務(wù)在分發(fā)之后,并不會(huì)等待任務(wù)完成,在任務(wù)生命期中,可以繼續(xù)分發(fā)其他任務(wù)。但任何任務(wù)都會(huì)結(jié)束,很多時(shí)候我們需要知道異步任務(wù)何時(shí)完成,以及任務(wù)的完成情況、任務(wù)返回的結(jié)果,以便該任務(wù)后續(xù)的處理。比如,在燒水完成之后,我們需要處理 沖水 的任務(wù)。

這就要涉及到一個(gè)對(duì)異步而言非常重要的概念:

回調(diào): 任務(wù)在生命期間向機(jī)體提供通知的方式。

比如 燒水 任務(wù)完成后,燒水壺 “叮” 的一聲通知任務(wù)完成;或者燒水期間發(fā)生故障,發(fā)出報(bào)警提示。這種在任務(wù)生命期間向機(jī)體發(fā)送通知的方式稱為回調(diào) 。在編程中,回調(diào)一般是通過(guò) 函數(shù)參數(shù) 來(lái)實(shí)現(xiàn)的,所以習(xí)慣稱 回調(diào)函數(shù) 。 另外,函數(shù)可以傳遞數(shù)據(jù),所以通過(guò)回調(diào)函數(shù)不僅可以知道任務(wù)結(jié)束的契機(jī),還可以通過(guò)回調(diào)參數(shù)將任務(wù)的內(nèi)部數(shù)據(jù)暴露給機(jī)體。

比如在實(shí)際開(kāi)發(fā)中,分發(fā) 網(wǎng)絡(luò)數(shù)據(jù)獲取 的任務(wù),其目的是為了通過(guò)網(wǎng)絡(luò)接口獲取數(shù)據(jù)。就像燒開(kāi)水任務(wù)完成之后,需要把 開(kāi)水 倒入瓶中一樣。我們也需要知道 網(wǎng)絡(luò)數(shù)據(jù)獲取 的任務(wù)完成的時(shí)機(jī),將獲取的數(shù)據(jù) "倒入" 界面中進(jìn)行顯示。

從發(fā)送異步任務(wù),到異步任務(wù)結(jié)束的回調(diào)觸發(fā),就是一個(gè)異步任務(wù)完整的 生命期。

三、 Dart 語(yǔ)言中的異步

上面只是介紹了 異步模型 中的概念,這些概念是共通的,無(wú)論什么編程語(yǔ)言都一樣適用。就像現(xiàn)實(shí)中,無(wú)論使用哪國(guó)的語(yǔ)言表述,四則運(yùn)算的概念都不會(huì)有任何區(qū)別。只是在表述過(guò)程中,表現(xiàn)形式會(huì)在語(yǔ)言的語(yǔ)法上有所差異。

1.編程語(yǔ)言中與異步模型的對(duì)應(yīng)關(guān)系

每種語(yǔ)言的描述,都是對(duì)概念模型的具象化實(shí)現(xiàn)。這里既然是對(duì) Flutter 中異步編程的介紹,自然要說(shuō)一下 Dart 語(yǔ)言對(duì)異步模型的描述。

對(duì)于 任務(wù) 概念來(lái)說(shuō),在編程中和 函數(shù) 有著千絲萬(wàn)縷的聯(lián)系:函數(shù)體 可以實(shí)現(xiàn) 任務(wù)處理的具體邏輯,也可以觸發(fā) 任務(wù)分發(fā)的動(dòng)作 。但我并不認(rèn)為兩者是等價(jià)的, 任務(wù) 有著明確的 目的性 ,而 函數(shù) 是實(shí)現(xiàn)這種 目的 的手段。在編程活動(dòng)中,函數(shù) 作為 任務(wù) 在代碼中的邏輯體現(xiàn),任務(wù) 應(yīng)先于 函數(shù) 存在。

如下代碼所示,在 main 函數(shù)中,觸發(fā) calculate 任務(wù),計(jì)算 0 ~ count 累加值和計(jì)算耗時(shí),并返回。其中 calculate 函數(shù)就是對(duì)該任務(wù)的代碼實(shí)現(xiàn):

void main(){
  TaskResult result = calculate();
}
TaskResult calculate({int count = 10000000}){
  int startTime = DateTime.now().millisecondsSinceEpoch;
  int result = loopAdd(count);
  int cost = DateTime.now().millisecondsSinceEpoch-startTime;
  return TaskResult(
    cost:cost,
    data:result,
    taskName: "calculate"
  );
}
int loopAdd(int count) {
  int sum = 0;
  for (int i = 0; i <= count; i++) {
    sum+=i;
  }
  return sum;
}

這里 TaskResult 類(lèi)用于記錄任務(wù)完成的信息:

class TaskResult {
  final int cost;
  final String taskName;
  final dynamic data;
  TaskResult({
    required this.cost,
    required this.data,
    required this.taskName,
  });
  Map<String,dynamic> toJson()=>{
    "taskName":taskName,
    "cost":cost,
    "data": data
  };
}

2.Dart 編程中的異步任務(wù)

如下在計(jì)算之后,還有兩個(gè)任務(wù):saveToFile 任務(wù),將運(yùn)算結(jié)果保存到文件中;以及 render 任務(wù)將運(yùn)算結(jié)果渲染到界面上。

void main() {
  TaskResult result = cacaulate();
  saveToFile(result);
  render(result);
}

這里 render 任務(wù)暫時(shí)通過(guò)在控制臺(tái)打印顯示作為渲染,邏輯如下:

void render(TaskResult result) {
  print("結(jié)果渲染: ${result.toJson()}");
}

下面是將結(jié)果寫(xiě)入文件的任務(wù)實(shí)現(xiàn)邏輯。其中 File 對(duì)象的 writeAsString 是一個(gè)異步方法,可以將內(nèi)容寫(xiě)入到文件中。通過(guò) then 方法設(shè)置回調(diào),監(jiān)聽(tīng)任務(wù)完成的時(shí)機(jī)。

void saveToFile(TaskResult result) {
  String filePath = path.join(Directory.current.path, "out.json");
  File file = File(filePath);
  String content = json.encode(result);
  file.writeAsString(content).then((File value){
    print("寫(xiě)入文件成功:!${value.path}");
  });
}

3.當(dāng)前任務(wù)分析

如下是這三個(gè)任務(wù)的執(zhí)行示意,在 saveToFile 中使用 writeAsString 方法將異步處理寫(xiě)入邏輯。

這樣就像在燒水任務(wù)分發(fā)后,可以執(zhí)行曬被一樣。saveToFile 任務(wù)分發(fā)之后,不需要等待文件寫(xiě)入完成,可以繼續(xù)執(zhí)行 render 方法。日志輸出如下:渲染任務(wù)的執(zhí)行并不會(huì)因?qū)懭胛募蝿?wù)而阻塞,這就是異步處理的價(jià)值。

四、異步模型的延伸

1. 單線程異步模型的局限性

本文主要介紹 異步模型 的概念,認(rèn)識(shí)異步的作用,以及 Dart 編程語(yǔ)言中異步方法的基本使用。至于代碼中更具體的異步使用方式,將在后期文章中結(jié)合詳細(xì)介紹。另外,一般情況下,Dart 是以 單線程 運(yùn)行的,所以本文中強(qiáng)調(diào)的是 單線程 下的異步模型。

仔細(xì)思考一下,可以看出,單線程中實(shí)現(xiàn)異步是有局限性的。比如說(shuō)需要解析一個(gè)很大的 json ,或者進(jìn)行復(fù)雜的邏輯運(yùn)算等 耗時(shí)任務(wù),這種必須由 本機(jī)體 處理的邏輯,而不是 等待結(jié)果 的場(chǎng)景,是無(wú)法在單線程中異步處理的。

就像是 掃地 和 曬被 任務(wù),對(duì)于單一機(jī)體來(lái)說(shuō),不可能同時(shí)參與到兩個(gè)任務(wù)之中。在實(shí)際開(kāi)發(fā)中這兩個(gè)任務(wù)可類(lèi)比為 解析超大 json 和 顯示解析中界面 兩個(gè)任務(wù)。如果前者耗時(shí)三秒,由于單線程 中同步方法的阻塞,界面就會(huì)卡住三秒,這就是單線程異步模型的 局限性。

2. 多線程與異步的關(guān)系

上面問(wèn)題的本質(zhì)矛盾是:一個(gè)機(jī)體無(wú)法 同時(shí) 參與到兩件任務(wù) 具體執(zhí)行過(guò)程中。解決方案也非常簡(jiǎn)單,一個(gè)人搞不定,就搖人唄。多個(gè)機(jī)體參與任務(wù)分配的場(chǎng)景,就是 多線程 。 很多人都會(huì)討論 異步 和 多線程 的關(guān)系,其實(shí)很簡(jiǎn)單:兩個(gè)機(jī)體,一個(gè) 掃地,一個(gè) 曬被,同一時(shí)刻,存在兩個(gè)及以上的任務(wù)在生命期中,一定是異步的。毫無(wú)疑問(wèn),多線程 是 異步模型 的一種實(shí)現(xiàn)方式。

3. Dart 中如何解決單線程異步模型的局限性

像 C++ 、Java 這些語(yǔ)言有 多線程 的支持,通過(guò) “搖人” 可以充分調(diào)度 CPU 核心,來(lái)處理一些計(jì)算密集型的任務(wù),實(shí)現(xiàn)任務(wù)在時(shí)間上的最合理分配。

絕大多數(shù)人可能覺(jué)得 Dart 是一個(gè)單線程的編程語(yǔ)言,其實(shí)不然??赡苁呛芏嗳瞬](méi)有在 Flutter 端做過(guò)計(jì)算密集型的任務(wù),沒(méi)有對(duì)多線程迫切的需要。畢竟 移動(dòng)/桌面客戶端 大多是網(wǎng)絡(luò)、數(shù)據(jù)庫(kù)訪問(wèn)等 io 密集型 的任務(wù),人手一個(gè)終端,沒(méi)有什么高并發(fā)的場(chǎng)景。不像后端那樣需要保證一個(gè)終端被百萬(wàn)人同時(shí)訪問(wèn)。

或者計(jì)算密集型的任務(wù)都有由平臺(tái)機(jī)體進(jìn)行處理,將結(jié)果通知給 Flutter 端。這導(dǎo)致 Dart 看起來(lái)更像是一個(gè) 任務(wù)分發(fā)者,發(fā)號(hào)施令的人,絕大多數(shù)時(shí)候并不需要親自參與任務(wù)的執(zhí)行過(guò)程中。而這正是單線程下的異步模型所擅長(zhǎng)的:借他人之力,監(jiān)聽(tīng)回調(diào)信息。

其實(shí)我們?cè)谌粘i_(kāi)發(fā)中,使用的平臺(tái)相關(guān)的插件,其中的方法基本上都是異步的,本質(zhì)上就是這個(gè)原因。平臺(tái) 是個(gè)燒水壺,燒水任務(wù)只需要分發(fā) 和 監(jiān)聽(tīng)回調(diào)。至于水怎么燒開(kāi),是 平臺(tái) 需要關(guān)心的,這和 網(wǎng)絡(luò) io 、磁盤(pán) io 是很類(lèi)似的,都是 請(qǐng)求 與 響應(yīng) 的模式。這種任務(wù),由單線程的異步模型進(jìn)行處理,是最有效的,畢竟 “搖人” 還是要管飯的。

那如果非要在 Dart 中處理計(jì)算密集型的任務(wù),該如何是好呢?不用擔(dān)心,Dart 的 isolate 機(jī)制可以完成這項(xiàng)需求。關(guān)于這點(diǎn),在后面會(huì)進(jìn)行詳述。認(rèn)識(shí) 異步 是什么,是本文的核心,那本文就到這里,謝謝觀看 ~

更多關(guān)于Flutter 單線程異步模型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論