作者 / Michael Thomsen, Dart & Flutter Product Manager, Google
我們已經(jīng)正式發(fā)布了 Dart SDK 的 2.15 版本,該版本新增了可快速并發(fā)的工作器 isolate、新的構(gòu)造函數(shù)拆分 (tear-off) 語(yǔ)言特性、經(jīng)過(guò)改進(jìn)的 dart:core 庫(kù)枚舉支持、package 發(fā)布者相關(guān)的新功能,等等。
工作器 isolate 的快速并發(fā)
如今,幾乎所有現(xiàn)代設(shè)備都使用多核 CPU,可以并行執(zhí)行多個(gè)任務(wù)。對(duì)于大多數(shù) Dart 程序來(lái)說(shuō),這些內(nèi)核的使用情況對(duì)開(kāi)發(fā)者而言是透明的: 默認(rèn)情況下,Dart 運(yùn)行時(shí)系統(tǒng)在單個(gè)內(nèi)核上運(yùn)行所有的 Dart 代碼,不過(guò)會(huì)使用其他內(nèi)核來(lái)執(zhí)行系統(tǒng)級(jí)任務(wù),比如異步輸入/輸出,包括寫入文件或者調(diào)用網(wǎng)絡(luò)等。
不過(guò)您自己的 Dart 代碼可能也需要并發(fā)運(yùn)行。例如,您可能需要展示一個(gè)連續(xù)的動(dòng)畫,同時(shí)執(zhí)行一個(gè)長(zhǎng)時(shí)間運(yùn)行的任務(wù),比如解析一個(gè)大型 JSON 文件。如果額外任務(wù)花了太長(zhǎng)時(shí)間,就可能會(huì)導(dǎo)致界面卡頓或延遲。如果將這些額外的任務(wù)移動(dòng)到另一個(gè)單獨(dú)的內(nèi)核,動(dòng)畫就可以在主執(zhí)行線程上繼續(xù)運(yùn)行而不受干擾。
Dart 的并發(fā)模型基于 isolate,isolate 是一種相互隔離的獨(dú)立執(zhí)行單元,這是為了避免出現(xiàn)與共享內(nèi)存相關(guān)的大量并發(fā)編程錯(cuò)誤,如數(shù)據(jù)爭(zhēng)用等競(jìng)態(tài)條件。Dart 通過(guò)禁止在 isolate 之間共享任何可變對(duì)象來(lái)避免這些錯(cuò)誤,并使用消息傳遞在 isolate 之間交換狀態(tài)。在 Dart 2.15 中,我們對(duì) isolate 進(jìn)行了許多實(shí)質(zhì)性的改進(jìn)。
Dart 中的并發(fā) https://dart.dev/guides/language/concurrency
競(jìng)態(tài)條件 https://en.wikipedia.org/wiki/Race_condition#In_software
在 isolate 間發(fā)送多條消息 https://dart.dev/guides/language/concurrency#sending-multiple-messages-between-isolates
我們首先重新設(shè)計(jì)和實(shí)現(xiàn)了 isolate 的工作方式,引入了一個(gè)新概念: isolate 組。Isolate 組中的 isolate 共享各種內(nèi)部數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)則表示正在運(yùn)行的程序。這使得組中的單個(gè) isolate 變得更加輕便。如今,因?yàn)椴恍枰跏蓟绦蚪Y(jié)構(gòu),在現(xiàn)有 isolate 組中啟動(dòng)額外的 isolate 比之前快 100 多倍,并且產(chǎn)生的 isolate 所消耗的內(nèi)存減少了 10 至 100 倍。
雖然 isolate 組仍然阻止在 isolate 間共享訪問(wèn)可變對(duì)象,但由于 isolate 組使用共享堆實(shí)現(xiàn),這也讓其擁有了更多的功能。我們可以將對(duì)象從一個(gè) isolate 傳遞到另一個(gè) isolate,這可用于執(zhí)行返回大量?jī)?nèi)存數(shù)據(jù)的任務(wù)的工作器 isolate。例如,工作器 isolate 通過(guò)網(wǎng)絡(luò)調(diào)用獲得數(shù)據(jù),將該數(shù)據(jù)解析為大型 JSON 對(duì)象圖,然后將這個(gè) JSON 圖返回到主 isolate 中。在推出 Dart 2.15 之前,執(zhí)行該操作需要深度復(fù)制,如果復(fù)制花費(fèi)的時(shí)間超過(guò)幀預(yù)算時(shí)間,就會(huì)導(dǎo)致界面卡頓。
在 Dart 2.15 中,工作器 isolate 可以調(diào)用 Isolate.exit(),將其結(jié)果作為參數(shù)傳遞。然后,Dart 運(yùn)行時(shí)將包含結(jié)果的內(nèi)存數(shù)據(jù)從工作器 isolate 傳遞到主 isolate 中,無(wú)需復(fù)制,且主 isolate 可以在固定時(shí)間內(nèi)接收結(jié)果。我們已經(jīng)在 Flutter 2.8 中更新了 compute() 實(shí)用函數(shù),來(lái)利用 Isolate.exit()。如果您已經(jīng)在使用 compute(),那么在升級(jí)到 Flutter 2.8 后,您將自動(dòng)獲得這些性能提升。
Isolate.exit() https://api.dart.cn/stable/2.15.0/dart-isolate/Isolate/exit.html
compute() https://api.flutter-io.cn/flutter/foundation/compute-constant.html
最后,我們還重新設(shè)計(jì)了 isolate 消息傳遞機(jī)制的實(shí)現(xiàn)方式,使得中小型消息的傳遞速度提高了大約 8 倍。發(fā)送消息的速度明顯更快,而接收信息幾乎總是在恒定的時(shí)間內(nèi)完成。另外,我們擴(kuò)展了 isolate 可以相互發(fā)送的對(duì)象種類,增加了對(duì)函數(shù)類型、閉包和堆棧跟蹤對(duì)象的支持。請(qǐng)參閱 SendPort.send() 的 API 文檔了解詳情:
https://api.dart.cn/stable/2.15.0/dart-isolate/SendPort/send.html
要了解有關(guān)如何使用 isolate 的更多信息,請(qǐng)參閱我們?yōu)?Dart 2.15 添加的官方文檔 Dart 中的并發(fā),以及更多代碼示例。
Dart 中的并發(fā) https://dart.cn/guides/language/concurrency
代碼示例 https://github.com/dart-lang/samples/tree/master/isolates
新語(yǔ)言特性:構(gòu)造函數(shù)拆分
在 Dart 中,您可以使用函數(shù)名稱創(chuàng)建一個(gè)函數(shù)對(duì)象,該對(duì)象指向另一個(gè)對(duì)象的函數(shù)。在以下示例中,main() 方法的第二行演示了將 g 指向 m.greet 的語(yǔ)法:
class Greeter { final String name; Greeter(this.name); void greet(String who) { print('$name says: Hello $who!'); }}void main() { final m = Greeter('Michael'); final g = m.greet; // g holds a function pointer to m.greet. g('Leaf'); // Invokes and prints "Michael says: Hello Leaf!"}
在使用 Dart 核心庫(kù)時(shí),這種函數(shù)指針 (也被稱為函數(shù)拆分) 經(jīng)常出現(xiàn)。下面是通過(guò)傳遞函數(shù)指針在 iterable 上調(diào)用 foreach() 的示例:
final m = Greeter('Michael');['Lasse', 'Bob', 'Erik'].forEach(m.greet);// Prints "Michael says: Hello Lasse!", "Michael says: Hello Bob!",// "Michael says: Hello Erik!"
在之前的版本中,Dart SDK 不支持創(chuàng)建構(gòu)造函數(shù)的拆分 (語(yǔ)言問(wèn)題 #216)。這就有點(diǎn)煩人,因?yàn)樵谠S多情況下,例如構(gòu)建 Flutter 界面時(shí),就需要用到構(gòu)造函數(shù)的拆分。從 Dart 2.15 開(kāi)始,我們支持這種語(yǔ)法。以下是構(gòu)建包含三個(gè) Text widget 的 Column widget 的示例,通過(guò)調(diào)用 .map() 將 Text 構(gòu)造函數(shù)的拆分傳遞給 Column 的子項(xiàng)。
class FruitWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: ['Apple', 'Orange'].map(Text.new).toList()); }}
#216: 允許像傳遞方法一樣傳遞構(gòu)造函數(shù)
https://github.com/dart-lang/language/issues/2
Text.new 指 Text 類的默認(rèn)構(gòu)造函數(shù)。您也可以引用命名構(gòu)造函數(shù),例如 .map(Text.rich)。
相關(guān)語(yǔ)言變化
在實(shí)現(xiàn)構(gòu)造函數(shù)拆分時(shí),我們也借此機(jī)會(huì)修復(fù)了現(xiàn)有的函數(shù)指針功能中的一些不一致問(wèn)題。現(xiàn)在可以特化泛型方法來(lái)創(chuàng)建非泛型方法:
T id(T value) => value;var intId = id ; // New in 2.15.int Function(int) intId = id; // Pre-2.15 workaround.
您甚至可以特化一個(gè)泛型函數(shù)對(duì)象來(lái)創(chuàng)建一個(gè)非泛型函數(shù)對(duì)象:
const fo = id; // Tear off `id`, creating a function object.const c1 = fo; // New in 2.15; error before.
最后,Dart 2.15 清理了涉及泛型的類型字面量:
var y = List; // Already supported.var z = List; // New in 2.15.var z = typeOf >(); // Pre-2.15 workaround.
改進(jìn) dart:core 庫(kù)中的枚舉
我們?yōu)?dart:core 庫(kù)的枚舉 API 添加了許多優(yōu)化 (語(yǔ)言問(wèn)題 #1511)。現(xiàn)在您可以通過(guò) .name 獲取每個(gè)枚舉值的 String 值:
enum MyEnum { one, two, three}void main() { print(MyEnum.one.name); // Prints "one".}
#1511: 為枚舉值添加 name 實(shí)例屬性 https://github.com/dart-lang/language/issues/1511
還可以按名稱查找枚舉值:
print(MyEnum.values.byName('two') == MyEnum.two); // Prints "true".
最后,您可以獲得所有名稱-值對(duì)的映射:
final map = MyEnum.values.asNameMap();print(map['three'] == MyEnum.three); // Prints "true".
請(qǐng)參閱此 Flutter PR 查看這些新 API 的使用示例:
https://github.com/flutter/flutter/pull/94496/files
壓縮指針
Dart 2.15 增加了對(duì)壓縮指針的支持,這樣,如果只需要支持 32 位的地址空間 (最多 4 GB 內(nèi)存),則 64 位 SDK 可以使用更加節(jié)省空間的指針表示形式。壓縮指針顯著減少了內(nèi)存占用,在對(duì) Google Pay 應(yīng)用的內(nèi)部測(cè)試中,我們發(fā)現(xiàn) Dart 堆的體積減少了大約 10%。
壓縮指針意味著無(wú)法處理 4 GB 以上的可用 RAM,因此該功能只存在于 Dart SDK 的配置選項(xiàng)中,只能在構(gòu)建 SDK 時(shí)由 Dart SDK 的嵌入器啟用。Flutter SDK 2.8 版已為 Android 構(gòu)建啟用此配置,F(xiàn)lutter 團(tuán)隊(duì)正在考慮在后續(xù)版本中為 iOS 構(gòu)建啟用此配置:
https://github.com/flutter/flutter/issues/94753
Dart SDK 中包含 Dart DevTools
以往 Dart SDK 不提供調(diào)試和性能工具的 DevTools 套件,您需要單獨(dú)下載。從 Dart 2.15 開(kāi)始,下載 Dart SDK 時(shí)也會(huì)獲取 DevTools,無(wú)需進(jìn)一步的安裝步驟。有關(guān)在 Dart 命令行應(yīng)用中使用 DevTools 的更多信息,請(qǐng)參閱 DevTools 文檔:
https://dart.dev/tools/dart-devtools#using-devtools-with-a-command-line-app
DevTools套件
https://dart.dev/tools/dart-devtools#
面向 package 發(fā)布者的新 pub 功能
Dart 2.15 SDK 在 dart pub 開(kāi)發(fā)者命令和 pub.devpackage repo 中還新增了兩個(gè)功能。 首先,為 package 發(fā)布者新增了一個(gè)安全功能,用于檢測(cè)發(fā)布者在 pub package 中意外發(fā)布 secret,例如 Cloud 或 CI 憑據(jù)。在了解到 GitHub repo 中每天都有數(shù)以千計(jì)的 secret 被泄露后,我們便決定添加這個(gè)泄露檢測(cè)功能。
公共 GitHub repo 的 secret 泄漏有多嚴(yán)重?
https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_04B-3_Meli_paper.pdf
泄露檢測(cè)作為 dart pub publish 命令中的預(yù)發(fā)布驗(yàn)證的一部分運(yùn)行。如果它在即將發(fā)布的文件中檢測(cè)到潛在的 secret,publish 命令會(huì)退出,而不進(jìn)行發(fā)布,并打印如下輸出:
Publishing my_package 1.0.0 to https://pub.dartlang.org:Package validation found the following errors:* line 1, column 1 of lib/key.pem: Potential leak of Private Key detected.?1 │ ┌ - - -BEGIN PRIVATE KEY - - -2 │ │ H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ3 │ └ - - -END PRIVATE KEY - - -?* line 2, column 23 of lib/my_package.dart: Potential leak of Google OAuth Refresh Token detected.?2 │ final refreshToken = "1//042ys8uoFwZrkCgYIARAAGAQSNwF-L9IrXmFYE-sfKefSpoCnyqEcsHX97Y90KY-p8TPYPPnY2IPgRXdy0QeVw7URuF5u9oUeIF0";
在極少數(shù)情況下,此項(xiàng)檢測(cè)可能會(huì)出現(xiàn)誤報(bào),將您實(shí)際上打算發(fā)布的內(nèi)容或文件標(biāo)記為潛在泄露。在這些情況下,您可以將文件添加到許可名單中:
https://dart.cn/tools/pub/pubspec#false_secrets
其次,我們還為發(fā)布者添加了另一個(gè)功能:撤銷已發(fā)布的 package 版本。當(dāng)發(fā)布了有問(wèn)題的 package 版本時(shí),我們通常的建議是發(fā)布一個(gè)小幅升級(jí)的新版本來(lái)修復(fù)意外問(wèn)題。但在極少數(shù)情況下,例如您尚未修復(fù)這些問(wèn)題,或是您在原打算只發(fā)布一個(gè)次要版本時(shí)意外發(fā)布了一個(gè)主要版本,那么您就可以使用新的 package 撤銷功能,作為最后的補(bǔ)救方法。此功能在 pub.dev 的管理界面中提供:
撤銷 package 版本
https://dart.cn/tools/pub/publishing#retract
在 package 版本被撤銷后,pub 客戶端在 pub get 或 pub upgrade 中將不再解析該版本。如果有開(kāi)發(fā)者已經(jīng)解析該撤銷的版本 (并存在于他們的 pubspec.lock 文件中),他們將在下次運(yùn)行 pub 時(shí)看到警告:
$ dart pub getResolving dependencies…mypkg 0.0.181-buggy (retracted, 0.0.182-fixed available)Got dependencies!
檢測(cè)雙向 Unicode 字符的安全性分析 (CVE-2021–22567)
最近發(fā)現(xiàn)了一個(gè)涉及雙向 Unicode 字符的通用編程語(yǔ)言漏洞 (CVE-2021–42574)。這個(gè)漏洞影響了大多數(shù)支持 Unicode 的現(xiàn)代編程語(yǔ)言。下面的 Dart 源代碼演示了這個(gè)問(wèn)題:
main() { final accessLevel = 'user'; if (accessLevel == 'user .?// Check if admin? ?') { print('You are a regular user.'); } else { print('You are an admin.'); }}
CVE-2021–42574 https://nvd.nist.gov/vuln/detail/CVE-2021-42574
您可能會(huì)認(rèn)為該程序會(huì)打印出 You are a regular user.,但實(shí)際上它打印出的是 You are an admin.!通過(guò)使用包含雙向 Unicode 字符的字符串,您就可能會(huì)造成這一漏洞。這些雙向字符針對(duì)在同一行的文本,可以將文本的方向由從左到右更改為從右到左,反之亦然。雙向字符文本在屏幕上的呈現(xiàn)與實(shí)際文本內(nèi)容截然不同。您可以進(jìn)一步查看此 GitHub gist 示例:
https://gist.github.com/mit-mit/7dda00ca6278ce7d2555f78d59d9e67b?h=1
針對(duì)此漏洞的緩解措施包括使用檢測(cè)雙向 Unicode 字符的工具 (編輯器、代碼審查工具等),以便開(kāi)發(fā)者發(fā)現(xiàn)它們,并在知情的情況下使用這些字符。上面提到的 GitHub gist 文件查看器便是發(fā)現(xiàn)這些字符的工具的一個(gè)例子。
Dart 2.15 引入了進(jìn)一步的緩解措施 (Dart 安全建議CVE-2021–22567)。現(xiàn)在,Dart 分析器會(huì)掃描雙向 Unicode 字符,并標(biāo)記對(duì)它們的任何使用:
$ dart analyzeAnalyzing cvetest... 2.6sinfo ? bin/cvetest.dart:4:27 ? The Unicode code point 'U+202E' changes the appearance of text from how it's interpreted by the compiler. Try removing the code point or using the Unicode escape sequence 'u202E'. ? text_direction_code_point_in_literal
Dart 安全建議 CVE-2021–22567 https://github.com/dart-lang/sdk/security/advisories/GHSA-8pcp-6qc9-rqmv
我們建議用 Unicode 轉(zhuǎn)義序列替換這些字符,這樣它們就可在任何文本編輯器或查看器中顯示出來(lái)。或者,如果您確實(shí)正當(dāng)使用了這些字符,您可以在使用這些字符的代碼行之前添加覆蓋語(yǔ)句來(lái)禁用警告:
// ignore: text_direction_code_point_in_literal
使用第三方 pub 服務(wù)器時(shí)的 pub.dev 憑據(jù)漏洞 (CVE-2021–22568)
我們也發(fā)布了第二個(gè)與 pub.dev 相關(guān)的 Dart 安全建議:CVE-2021–22568。此建議針對(duì)可能將 package 發(fā)布到第三方 pub package 服務(wù)器 (例如私人或公司內(nèi)部 package 服務(wù)器) 的 package 發(fā)布者。僅將 package 發(fā)布到公開(kāi) pub.dev repo (標(biāo)準(zhǔn)配置) 的開(kāi)發(fā)者不受此漏洞的影響。
CVE-2021–22568 https://github.com/dart-lang/sdk/security/advisories/GHSA-r32f-vhjp-qhj7
如果您已經(jīng)將 package 發(fā)布至第三方 repo,那么漏洞是:用于在第三方 repo 進(jìn)行身份驗(yàn)證的 OAuth2 臨時(shí) (一小時(shí)) 訪問(wèn)令牌可能被誤用,以在公開(kāi) pub.dev repo 上進(jìn)行身份驗(yàn)證。因此惡意的第三方 pub 服務(wù)器可能會(huì)使用訪問(wèn)令牌,在 pub.dev 上冒充您,并發(fā)布 package。如果您已經(jīng)將 package 發(fā)布到一個(gè)不受信任的第三方 package repo,請(qǐng)考慮審查您的帳號(hào)在 pub.dev 公開(kāi) package repo 上的所有活動(dòng)。我們推薦您使用 pub.dev 活動(dòng)日志進(jìn)行查看:
https://pub.dev/my-activity-log
最后
希望您喜歡已經(jīng)推出的 Dart 2.15 中的新功能。這是我們今年的最后一個(gè)版本,我們想借此機(jī)會(huì)表達(dá)我們對(duì)美妙的 Dart 生態(tài)系統(tǒng)的感謝。感謝大家的寶貴反饋,以及對(duì)我們一直以來(lái)的支持,感謝大家在過(guò)去的一年中在 pub.dev 上發(fā)布的數(shù)千個(gè) package,它們豐富了我們的生態(tài)系統(tǒng)。我們迫切期待明年再次投入工作,我們計(jì)劃在 2022 年推出很多激動(dòng)人心的內(nèi)容。預(yù)祝大家新年快樂(lè),好好享受即將到來(lái)的假期吧!
原文標(biāo)題:Dart 2.15 現(xiàn)已發(fā)布
文章出處:【微信公眾號(hào):谷歌開(kāi)發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4344瀏覽量
62864 -
SDK
+關(guān)注
關(guān)注
3文章
1045瀏覽量
46131 -
GitHub
+關(guān)注
關(guān)注
3文章
473瀏覽量
16524
原文標(biāo)題:Dart 2.15 現(xiàn)已發(fā)布
文章出處:【微信號(hào):Google_Developers,微信公眾號(hào):谷歌開(kāi)發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論