官宣.NET 6 預覽版4
我們很高興發布 .NET 6 Preview 4。我們現在大約完成了 .NET 6 發布的一半。現在是一個很好的時機,可以再次查看.NET6的完整範圍。許多功能都接近最終形式,而其他功能將很快推出,因為發布的基礎構建塊已經就緒。預覽版 4 為在 11 月交付最終的 .NET 6 構建奠定了堅實的基礎,並提供了完整的功能和體驗。如果您還沒有在您的環境中嘗試過 .NET 6,那麼您現在可以用拉。
說到最終版本,我們現在有一個日期了! 預計在11 月 9 日至 11 日的.NET Conf 2021。我們將在 9 日發布 .NET 6,其中包含許多深入的演講和演示,告訴您有關 .NET 6 的所有資訊。
您可以下載適用於 Linux、macOS 和 Windows 的 .NET 6 預覽版4。
有關 Web 和數據訪問方案的新增功能的更多詳細資訊,請參閱 ASP.NET Core和 EF Core帖子。 還有新的 .NET MAUI帖子描述了新的客戶端應用程式體驗,還有一個熱重載帖子描述了提高開發人員生產力的新方法。
.NET 6 已經過 Visual Studio 16.11 和 Visual Studio for Mac 8.9 的測試。 如果您想在Visual Studio 中試用 .NET 6,我們建議您使用這些版本。
Build 2021
Microsoft Build大會已經舉行了。你肯定會想看看這些演講,其中將包含大量關於 .NET 6 的討論和演示,向你展示新功能和現在可能實現的功能。
.NET 6 主題
我們於 2020 年底開始在 GitHub 上規劃 .NET 6。我們在一系列廣泛的主題中確定了八個主題,包括行業場景、支援和教育。這些主題代表了我們發布工作的一半到四分之三。有很多項目沒有上升到主題的水平,或者意義重大但不是主題(例如支援 Apple Silicon 設備)。
以下是 .NET 6 主題,每個主題都用一句話總結描述。 它們按照在 themesof.net 中顯示的相同順序列出。
-
.NET 對新開發人員和學生具有吸引力— 在 Visual Studio產品中提供有意簡化的體驗,包括清晰的文檔、更簡單的程式碼模型和更少的文件和概念,以及將工件部署到測試和生產環境的直觀路徑。
-
.NET 擁有出色的客戶端應用程式開發體驗— 提供跨平台客戶端應用程式基礎,可無縫滿足桌面、移動和 Web 開發人員的需求,並基於 Blazor 和 Xamarin 等現有應用程式類型進行構建和擴展。
-
.NET 被公認為構建雲原生應用程式的引人注目的框架——提供主要針對性能和可觀察性的基本雲原生功能,改進與雲原生和容器生態系統的集成,以及一個雲原生組件 (yarp),它展示了很多.NET 的價值與關鍵的雲用例。
-
企業和 LTS —提供更簡單、更可預測的模型,以將 .NET 與關鍵任務應用程式結合使用,並更好地滿足大型企業和政府客戶的需求。
-
通過提高品質、信心和支援來發展 .NET 生態系統——建立長期的社區合作,旨在將社區開發人員提升到與 Microsoft 類似的水平,並(另一方面)提供新的功能和體驗,使其成為企業開發人員更容易依賴社區開源項目中的庫,而社區開源項目不一定與大公司有關聯或得到大公司的支援。
-
提高 .NET 開發人員的內循環性能——提高開發人員的工作效率,包括提高構建性能、熱重啟和熱重載。
-
使用運行時執行資訊 (PGO)提高啟動和吞吐量 —提供基於運行時資訊的新模型以提高性能,可用於更快的啟動、更高的吞吐量和更小的二進位文件。
-
滿足開發人員的期望 —根據回饋在整個 .NET 產品中進行改進,並啟用具有現有功能的新方案。
以下帖子更詳細地討論了其中一些主題:
.NET 平台統一
我們在過去的帖子和會議上討論了很多關於 .NET 統一的內容,但主題中缺少它。平台統一已經融入我們所做的一切,不需要自己的主題。人們可以將其視為超出所列主題的一個大主題。它貫穿多個主題,是團隊前進的基本假設。
內循環性能項目就是一個很好的例子。它假定 .NET 6 應用程式都共享相同的基礎,例如使用相同的構建系統和庫。如果存在技術差異,例如使用不同的運行時(CoreCLR 或 Mono)或程式碼生成技術(AOT 或 JIT),我們會考慮這些因素並提供務實和適當的體驗,並傾向於沒有可觀察到的體驗差異。EventPipe 項目是另一個類似的例子。
產品信心
我們將很快開始發布生產支援的”上線”版本。我們目前的目標是 8 月。我們的開發模型以啟用生產工作負載為導向,即使我們正在完成剛剛提到的所有主題的工作。
產品信心始於 dotnet.microsoft.com 站點。從預覽版 1 開始,它在 .NET 6上運行了一半的站點負載。雖然規模不大,但它是我們團隊的關鍵任務站點,我們非常重視它。.NET 6 一直像冠軍一樣為我們工作。
我們還與在 .NET 預覽版上部署生產應用程式的 Microsoft 團隊合作。他們這樣做是為了儘早利用新的 .NET 功能。這些團隊一直在尋找降低雲託管成本的機會,並且部署新的 .NET 版本已被證明是最有效和最省力的方法之一。這些團隊為我們提供早期回饋,幫助我們確保新功能已準備好供全球生產使用。他們還顯著影響最終特徵形狀,因為他們是我們的第一批生產用戶。
所有這些與實際應用程式的早期實戰測試讓我們相信 .NET 6 將準備好運行您的應用程式。
文章的其餘部分專門介紹預覽版 4 中的新功能。
工具:使用 Visual Studio 調試器和 dotnet CLI 進行熱重載
熱重載是一種新體驗,讓您可以在應用程式運行時對其源程式碼進行編輯,而無需手動暫停應用程式或點擊斷點。熱重載通過減少重新啟動正在運行的應用程式所需的次數來提高開發人員的工作效率。
在此版本中,熱重載適用於多種類型的應用程式,例如 WPF、Windows 窗體、WinUI、ASP.NET、控制台應用程式和其他運行在 CoreCLR 運行時之上的框架。 我們也在努力將這項技術引入在 Mono 之上運行的 WebAssembly、iOS 和 Android 應用程式,但這仍然會出現(在稍後的預覽版中)。
要開始測試此功能,請安裝 Visual Studio 2019 版本 16.11 預覽版 1 並使用 Visual Studio 調試器 (F5) 啟動您的應用。應用程式運行後,您現在可以使用新的選項來更改程式碼並使用新的”應用程式碼更改”按鈕應用它們,如下圖所示。
熱重載也可通過 dotnet監視工具獲得。 預覽版 4 包含多個改進該體驗的修復程式。
如果您想了解有關熱重載的更多資訊,可以閱讀.NET熱重載的介紹。
System.Text.Json 對 IAsyncEnumerable 的支援
IAsyncEnumerable
以下示例使用流作為任何非同步數據源的表示。源可以是本地機器上的文件,也可以是資料庫查詢或 Web 服務 API 調用的結果。
流序列化
System.Text.Json 現在支援將 IAsyncEnumerable
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
static async IAsyncEnumerable<int> PrintNumbers(int n)
{
for (int i = 0; i < n; i++) yield return i;
}
using Stream stream = Console.OpenStandardOutput();
var data = new { Data = PrintNumbers(3) };
await JsonSerializer.SerializeAsync(stream, data); // prints {"Data":[0,1,2]}
IAsyncEnumerable 值僅支援使用非同步序列化方法。嘗試使用同步方法進行序列化將導致拋出 NotSupportedException。
流反序列化
流式反序列化需要一個返回 IAsyncEnumerable
using System;
using System.IO;
using System.Text;
using System.Text.Json;
var stream = new MemoryStream(Encoding.UTF8.GetBytes("[0,1,2,3,4]"));
await foreach (int item in JsonSerializer.DeserializeAsyncEnumerable<int>(stream))
{
Console.WriteLine(item);
}
此示例將按需反序列化元素,並且在使用特別大的數據流時非常有用。它只支援從根級別的JSON 數組中讀取,儘管將來可以根據回饋放寬。
現有的 DeserializeAsync 方法名義上支援 IAsyncEnumerable
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"{""Data"":[0,1,2,3,4]}"));
var result = await JsonSerializer.DeserializeAsync<MyPoco>(stream);
await foreach (int item in result.Data)
{
Console.WriteLine(item);
}
public class MyPoco
{
public IAsyncEnumerable<int> Data { get; set; }
}
在此示例中,反序列化器將在返回反序列化對象之前緩衝記憶體中的所有 IAsyncEnumerable 內容。這是因為反序列化器需要在返回結果之前消耗整個 JSON 值。
System.Text.Json:可寫 DOM 功能
可寫的 JSON DOM 功能為 System.Text.Json 添加了一個新的簡單高效的編程模型。這個新的 API 很有吸引力,因為它避免了序列化的複雜性和儀式以及 DOM 的傳統成本。
這個新的 API 有以下好處:
-
在不可能或不希望使用 POCO 類型的情況下,或者當 JSON 模式不固定且必須檢查時,序列化的輕量級替代方案。
-
允許對大樹的子集進行有效修改。例如,可以高效地導航到大型 JSON 樹的子部分並從該子部分讀取數組或反序列化 POCO。 LINQ 也可以與它一起使用。
-
允許使用 C# 動態關鍵字,這允許使用鬆散類型的、更像腳本的模型。
我們正在尋找有關支援動態的回饋。如果動態支援對您很重要,請給我們您的回饋。
在 dotnet/runtime #6098中提供了更多詳細資訊。
可寫的 DOM API
可寫 DOM 公開以下類型。
namespace System.Text.Json.Node
{
public abstract class JsonNode {...};
public sealed class JsonObject : JsonNode, IDictionary<string, JsonNode?> {...}
public sealed class JsonArray : JsonNode, IList<JsonNode?> {...};
public abstract class JsonValue : JsonNode {...};
}
示例程式碼
以下示例演示了新的編程模型。
// Parse a JSON object
JsonNode jNode = JsonNode.Parse("{"MyProperty":42}");
int value = (int)jNode["MyProperty"];
Debug.Assert(value == 42);
// or
value = jNode["MyProperty"].GetValue<int>();
Debug.Assert(value == 42);
// Parse a JSON array
jNode = JsonNode.Parse("[10,11,12]");
value = (int)jNode[1];
Debug.Assert(value == 11);
// or
value = jNode[1].GetValue<int>();
Debug.Assert(value == 11);
// Create a new JsonObject using object initializers and array params
var jObject = new JsonObject
{
["MyChildObject"] = new JsonObject
{
["MyProperty"] = "Hello",
["MyArray"] = new JsonArray(10, 11, 12)
}
};
// Obtain the JSON from the new JsonObject
string json = jObject.ToJsonString();
Console.WriteLine(json); // {"MyChildObject":{"MyProperty":"Hello","MyArray":[10,11,12]}}
// Indexers for property names and array elements are supported and can be chained
Debug.Assert(jObject["MyChildObject"]["MyArray"][1].GetValue<int>() == 11);
Microsoft.Extensions.Logging 編譯時源程式碼生成器
.NET 6 引入了 LoggerMessageAttribute 類型。此屬性是 Microsoft.Extensions.Logging 命名空間的一部分,使用時,它會生成performant日誌API。源程式碼生成日誌支援旨在為現代 .NET 應用程式提供高度可用且高性能的日誌解決方案。自動生成的源程式碼依賴於 ILogger 介面和 LoggerMessage.Define 功能。
當 LoggerMessageAttribute 用於部分日誌記錄方法時,將觸發源生成器。當被觸發時,它要麼能夠自動生成它正在裝飾的部分方法的實現,要麼產生帶有正確使用提示的編譯時診斷。編譯時日誌記錄解決方案在運行時通常比現有日誌記錄方法快得多。它通過最大限度地消除裝箱、臨時分配和拷貝來實現這一點。
直接手動使用 LoggerMessage.Define API 有以下好處:
-
更短更簡單的語法:聲明性屬性使用而不是程式碼樣板。
-
引導開發者體驗:生成器給出警告,幫助開發者做正確的事。
-
支援任意數量的日誌參數。 LoggerMessage.Define 最多支援六個。
-
支援動態日誌級別。單獨使用 LoggerMessage.Define 是不可能的。
-
如果您想跟蹤改進和已知問題,請參閱dotnet/runtime#52549。
基本用法
要使用 LoggerMessageAttribute,消費類和方法需要是部分的。
程式碼生成器在編譯時觸發,並生成部分方法的實現。
public static partial class Log
{
[LoggerMessage(EventId = 0, Level = LogLevel.Critical, Message = "Could not open socket to `{hostName}`")]
public static partial void CouldNotOpenSocket(ILogger logger, string hostName);
}
在前面的示例中,日誌記錄方法是靜態的,並且在屬性定義中指定了日誌級別。在靜態上下文中使用該屬性時,需要 ILogger 實例作為參數。您也可以選擇在非靜態上下文中使用該屬性。有關更多示例和使用場景,請訪問編譯時日誌源生成器的文檔。
System.Linq 增強功能
添加了社區請求和貢獻的新 System.LINQ API。
對索引和範圍參數的可枚舉支援
Enumerable.ElementAt 方法現在接受可枚舉對象末尾的索引,如下例所示。
Enumerable.Range(1, 10).ElementAt(\^2); // returns 9
添加了接受 Range 參數的 Enumerable.Take 重載。它簡化了可枚舉序列的切片:
-
source.Take(..3) 而不是 source.Take(3)
-
source.Take(3..) 而不是 source.Skip(3)
-
source.Take(2..7) 而不是 source.Take(7).Skip(2)
-
source.Take(^3..) 而不是 source.TakeLast(3)
-
source.Take(..^3) 而不是 source.SkipLast(3)
-
source.Take(^7..^3) 而不是 source.TakeLast(7).SkipLast(3).
感謝@dixin 對實施的貢獻。
TryGetNonEnumeratedCount
TryGetNonEnumeratedCount 方法嘗試在不強制枚舉的情況下獲取源可枚舉的計數。這種方法在枚舉之前預分配緩衝區很有用的情況下很有用,如下面的示例所示。
List<T> buffer = source.TryGetNonEnumeratedCount(out int count) ? new List<T>(capacity: count) : new List<T>();
foreach (T item in source)
{
buffer.Add(item);
}
TryGetNonEnumeratedCount 檢查實現 ICollection/ICollection
DistinctBy/UnionBy/IntersectBy/ExceptBy
新的變體已添加到 set 操作中,允許使用鍵選擇器函數指定相等性,如下面的示例所示。
Enumerable.Range(1, 20).DistinctBy(x => x % 3); // {1, 2, 3}
var first = new (string Name, int Age)[] { ("Francis", 20), ("Lindsey", 30), ("Ashley", 40) };
var second = new (string Name, int Age)[] { ("Claire", 30), ("Pat", 30), ("Drew", 33) };
first.UnionBy(second, person => person.Age); // { ("Francis", 20), ("Lindsey", 30), ("Ashley", 40), ("Drew", 33) }
MaxBy/MinBy
MaxBy 和 MinBy 方法允許使用鍵選擇器查找最大或最小元素,如下例所示。
var people = new (string Name, int Age)[] { ("Francis", 20), ("Lindsey", 30), ("Ashley", 40) };
people.MaxBy(person => person.Age); // ("Ashley", 40)
Chunk
Chunk 可用於將可枚舉的源分塊為固定大小的切片,如下例所示。
IEnumerable<int[]> chunks = Enumerable.Range(0, 10).Chunk(size: 3); // { {0,1,2}, {3,4,5}, {6,7,8}, {9} }
感謝 Robert Andersson 對實施的貢獻。
FirstOrDefault/LastOrDefault/SingleOrDefault 重載採用默認參數
如果源枚舉為空,現有的 FirstOrDefault/LastOrDefault/SingleOrDefault 方法返回 default(T)。添加了新的重載,接受在這種情況下要返回的默認參數,如下面的示例所示。
Enumerable.Empty<int>().SingleOrDefault(-1); // returns -1
感謝@Foxtrek64 對實現的貢獻。
接受三個枚舉的 Zip 重載
Zip方法現在支援組合三個可枚舉項,如下例所示。
var xs = Enumerable.Range(1, 10);
var ys = xs.Select(x => x.ToString());
var zs = xs.Select(x => x % 2 == 0);
foreach ((int x, string y, bool z) in Enumerable.Zip(xs,ys,zs))
{
}
感謝Huo Yaoyuan對實施的貢獻。
顯著提高了 Windows 上的 FileStream 性能
FileStream 已在 .NET 6 中重新編寫,以便在 Windows 上具有更高的性能和可靠性。
重寫項目已經分階段進行了五個 PR:
最終結果是 FileStream 在 Windows 上為非同步 IO 創建時永遠不會阻塞。這是一個重大的改進。 您可以在基準測試中觀察到這一點,我們很快就會看到。
配置
第一個 PR 使 FileStream 能夠在運行時選擇一個實現。這種模式最明顯的好處是可以切換回舊的 .NET 5 實現,您可以使用
runtimeconfig.json 中的以下設置來實現。
{
"configProperties": {
"System.IO.UseNet5CompatFileStream": true
}
}
我們計劃接下來添加一個 io_uring 策略,它利用了最近內核中同名的 Linux 功能。
性能基準
讓我們使用 BenchmarkDotNet來衡量改進。
public class FileStreamPerf
{
private const int FileSize = 1_000_000; // 1 MB
private Memory<byte> _buffer = new byte[8_000]; // 8 kB
[GlobalSetup(Target = nameof(ReadAsync))]
public void SetupRead() => File.WriteAllBytes("file.txt", new byte[FileSize]);
[Benchmark]
public async ValueTask ReadAsync()
{
using FileStream fileStream = new FileStream("file.txt", FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true);
while (await fileStream.ReadAsync(_buffer) > 0)
{
}
}
[Benchmark]
public async ValueTask WriteAsync()
{
using FileStream fileStream = new FileStream("file.txt", FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true);
for (int i = 0; i < FileSize / _buffer.Length; i++)
{
await fileStream.WriteAsync(_buffer);
}
}
[GlobalCleanup]
public void Cleanup() => File.Delete("file.txt");
}
ini BenchmarkDotNet=v0.13.0, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2) Intel Xeon CPU E5-1650 v4 3.60GHz, 1 CPU, 12 logical and 6 physical cores .NET SDK=6.0.100-preview.5.21267.9 [Host] : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT Job-OIMCTV : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT Job-CHFNUY : .NET 6.0.0 (6.0.21.26311), X64 RyuJIT
環境:Windows 10 與 SSD 驅動器啟用 BitLocker
結果:
-
現在讀取 1 MB 文件的速度提高了 2 倍,而寫入的速度提高了 4 倍。
-
記憶體分配從 39 KB 下降到 1 KB! 這是 97.5% 的改進!
這些更改將為 Windows 上的 FileStream 用戶提供顯著的改進。更多詳細資訊,請訪問 dotnet/core #6098。
增強的日期、時間和時區支援
對日期和時間相關的類型進行了以下改進。
新的 DateOnly 和 TimeOnly 結構
添加了僅限日期和時間的結構,具有以下特徵:
-
每個代表一個 DateTime 的一半,或者只是日期部分,或者只是時間部分。
-
DateOnly 是生日、周年紀念日和工作日的理想選擇。 它與 SQL Server 的日期類型一致。
-
TimeOnly 是定期會議、鬧鐘和每周工作時間的理想選擇。 它與 SQL Server 的時間類型一致。
-
補充現有的日期/時間類型(DateTime、DateTimeOffset、TimeSpan、TimeZoneInfo)。
-
在 System 命名空間中,在 CoreLib 中提供,就像現有的相關類型一樣。
對 DateTime.UtcNow 的性能改進
這種改進有以下好處:
-
修復了在 Windows 上獲取系統時間的 2.5 倍性能回歸。
-
利用 Windows 閏秒數據的 5 分鐘滑動快取,而不是在每次調用時獲取。
支援所有平台上的 Windows 和 IANA 時區
這種改進有以下好處:
-
使用 TimeZoneInfo.FindSystemTimeZoneById 時的隱式轉換 (//github.com/dotnet/runtime/pull/49412)
-
通過 TimeZoneInfo 上的新 API 進行顯式轉換:TryConvertIanaIdToWindowsId、TryConvertWindowsIdToIanaId
和 HasIanaId (//github.com/dotnet/runtime/issues/49407) -
改進了使用不同時區類型的系統之間的跨平台支援和互操作。
-
刪除需要使用 TimeZoneConverter OSS 庫。 該功能現已內置。
改進的時區顯示名稱
這種改進有以下好處:
-
從 TimeZoneInfo.GetSystemTimeZones 返回的列表中的顯示名稱中消除歧義。
-
利用 ICU / CLDR 全球化數據。
-
僅適用於 Unix。 Windows 仍然使用註冊表數據。 這可能會在以後更改。
其他
-
UTC 時區的顯示名稱和標準名稱被硬編碼為英語,現在使用與其餘時區數據相同的語言(Unix 上的 CurrentUICulture,Windows 上的作業系統默認語言)。
-
由於大小限制,WASM 中的時區顯示名稱改為使用非本地化的 IANA ID。
-
TimeZoneInfo.AdjustmentRule 嵌套類將其 BaseUtcOffsetDelta 內部屬性設為公開,並獲得一個以 baseUtcOffsetDelta 作為參數的新構造函數。(//github.com/dotnet/runtime/issues/50256
-
TimeZoneInfo.AdjustmentRule 還獲得了在 Unix 上載入時區的其他修復(//github.com/dotnet/runtime/pull/49733),(//github.com/dotnet/runtime/pull/50131)
CodeGen
對 RyuJIT 編譯器進行了以下改進。
社區貢獻
@SingleAccretion在過去幾個月中一直忙於進行以下改進。 這是 .NET 6 Preview 3的補充。謝謝!
-
dotnet/runtime #50373 — 如果樹是 CSE 候選者,不要摺疊雙重否定
-
dotnet/runtime #50450 — 處理通過助手完成的轉換和值編號中的摺疊溢出操作
-
dotnet/runtime #50702 — 刪除 GS Cookie 的 must-init 要求
-
dotnet/runtime #50703 — 不要混淆 fgMorphBlocks 中的 fgDispBasicBlocks
動態 PGO
已進行以下改進以支援動態 PGO。
-
dotnet/runtime #51664 — 更新 JIT 以使用從跨代處理的 PGO 數據中看到的新”LikelyClass”記錄
-
dotnet/runtime #50213 — 更好地容忍邊緣輪廓不一致
-
dotnet/runtime #50633 — 修復了混合 PGO/nonPGO 編譯
-
dotnet/runtime #50765 — 修改 fgExpandRunRarelyBlocks
-
dotnet/runtime #51593 — 修改內聯規模計算
JIT 循環優化
對循環優化進行了以下改進。
-
dotnet/runtime #50982 — 概括循環反轉
-
dotnet/runtime #51757 — 不要在循環克隆期間重新計算 preds 列表
LSRA
對線性掃描暫存器分配(LRSA)進行了以下改進。
- dotnet/runtime #51281 — 改進 LRSA 統計資訊以包括暫存器選擇啟發式資訊
優化
-
dotnet/runtime #49930 — 在值編號級別摺疊對 const 字元串的空檢查
-
dotnet/runtime #50000 — 針對 ref 類型的初始化靜態只讀欄位摺疊空檢查
-
dotnet/runtime #50112 — 不要在潛在的 BBJ_THROW 候選中分配字元串文字
-
dotnet/runtime #50644 — 為 VectorX.Create 啟用 CSE
-
dotnet/runtime #50806 — 如果後面有意外的塊,則放棄尾調用
-
dotnet/runtime #50832 — 更新 Vector
以支援 nint 和 nuint -
dotnet/runtime #51409 — 概括圍繞空流優化的分支
.NET 診斷:EventPipe for Mono 和改進的 EventPipe 性能
EventPipe 是 .NET 的跨平台機制,用於輸出事件、性能數據和計數器。 從 .NET 6 開始,我們已將實現從 C++ 移至 C。通過此更改,Mono 也將能夠使用EventPipe! 這意味著 CoreCLR 和 Mono 將使用相同的事件基礎結構,包括 .NET 診斷 CLI 工具!這一變化還伴隨著 CoreCLR 的小幅縮減:
我們還進行了一些更改,以提高負載下的 EventPipe 吞吐量。在前幾個預覽版中,我們進行了一系列更改,使吞吐量提高了 .NET 5 所能達到的2.06 倍:
- 使用 dotnet/diagnostics 中的 EventPipeStress 框架收集的數據。 編寫器應用程式在 60 秒內儘可能快地寫入事件。 記錄成功和丟棄事件的數量。
有關詳細資訊,請參閱 dotnet/runtime #45518。
IL 剪裁
默認啟用警告
剪裁警告告訴您剪裁可能會刪除運行時使用的程式碼的地方。這些警告以前在默認情況下被禁用,因為警告非常嘈雜,主要是由於.NET 平台沒有作為第一類方案參與剪裁。
我們對 .NET 庫(運行時庫,而不是 ASP.NET Core 或 Windows 桌面框架)的大部分進行了注釋,以便它們生成準確的剪裁警告。因此,我們認為是時候默認啟用剪裁警告了。
您可以通過將
剪裁警告為剪裁過程帶來了可預測性,並使開發人員掌握了權力。我們將繼續注釋更多 .NET 庫,包括後續版本中的 ASP.NET Core。我們希望社區也能通過注釋更多程式碼以確保安剪裁全來改善剪裁生態系統。
更多資訊:
默認剪裁模式=鏈接
.NET 6 中新的默認剪裁模式是鏈接。 鏈接 TrimMode 不僅可以剪裁未使用的程式集,還可以剪裁未使用的成員,從而顯著節省成本。
在 .NET 5 中,默認情況下剪裁會嘗試查找和刪除未引用的程式集。這更安全,但提供的好處有限。現在默認情況下剪裁警告處於啟用狀態,開發人員可以對剪裁結果充滿信心。
作為示例,讓我們通過剪裁其中一個 .NET SDK 工具來看看這種剪裁改進。
我將使用 crossgen,即準備運行的編譯器。它可以只用一些剪裁警告來剪裁,crossgen 團隊能夠解決這些問題。
首先,讓我們將 crossgen 發布為一個獨立的應用程式,無需剪裁。 它是 80
MB(包括 .NET 運行時和所有庫)。
然後我們可以嘗試(現在是舊版).NET 5 默認剪裁模式,copyused。 結果下降到 55 MB。
新的 .NET 6 默認剪裁模式鏈接將獨立文件大小進一步降低到 36MB。
我們希望新的鏈接剪裁模式能更好地滿足剪裁的期望:顯著節省和可預測的結果。
與 Native AOT 共享模型
我們也為 Native AOT 實驗實施了相同的剪裁警告,這應該會以大致相同的方式改善 Native AOT 編譯體驗。
單文件發布
對單文件應用程式發布進行了以下改進。
靜態分析
.NET 5 中添加了用於單文件發布的分析器,以警告 Assembly.Location
和其他一些在單文件包中表現不同的 API。
對於 .NET 6 Preview 4,我們改進了分析以允許自定義警告。如果您的 API 在單文件發布中不起作用,您現在可以使用 [RequiresAssemblyFiles] 屬性對其進行標記,如果啟用了分析器,則會出現警告。添加該屬性還將使方法中與單個文件相關的所有警告靜音,因此您可以使用該警告將警告向上傳播到您的公共 API。
當 PublishSingleFile 設置為 true 時,分析器會自動為 exe 項目啟用,但您也可以通過將 EnableSingleFileAnalysis 設置為 true 為任何項目啟用它。如果您想在單個文件包中嵌入庫,這可能會有所幫助。
壓縮
單文件包現在支援壓縮,這可以通過將屬性 EnableCompressionInSingleFile 設置為 true 來啟用。在運行時,根據需要將文件解壓縮到記憶體中。壓縮可以為某些場景提供巨大的空間節省。
讓我們看一下與 NuGet 包資源管理器一起使用的帶壓縮和不帶壓縮的單個文件發布。
無壓縮:172 MB
壓縮後:71.6 MB
壓縮可以顯著增加應用程式的啟動時間,尤其是在 Unix 平台上(因為它們具有無法與壓縮一起使用的無複製快速啟動路徑)。您應該在啟用壓縮後測試您的應用,看看額外的啟動成本是否可以接受。
PublishReadyToRun 現在默認使用 crossgen2
Crossgen2 現在在發布 ReadyToRun 影像時默認啟用。它還可選地支援生成合成影像。
公開以下設置,使您能夠使用準備運行的程式碼配置發布。這些設置被設為它們的默認值。
PublishReadyToRun 現在默認使用 crossgen2
Crossgen2現在在發布 ReadyToRun 影像時默認啟用。 它還可選地支援生成合成影像。
公開以下設置,使您能夠使用準備運行的程式碼配置發布。這些設置被設為它們的默認值。
.NET 6 SDK 可選工作負載的 CLI 安裝
.NET 6 將引入可以事後安裝在 .NET SDK 之上的 SDK 工作負載的概念,以支援各種場景。預覽版 4 中可用的新工作負載是 .NET MAUI 和 Blazor WebAssembly AOT 工作負載。
對於 .NET MAUI 工作負載,我們仍然建議使用預覽版 4 的 maui-check
工具,因為它包含 Visual Studio 中尚不可用的其他組件或作為 .NET SDK 工作負載。要嘗試 .NET SDK 體驗(以 iOS 為例),請運行 dotnet working install microsoft-ios-sdk-full。安裝後,您可以運行 dotnet new ios,然後運行 dotnet build 來創建和構建您的項目。
對於 Blazor WebAssembly AOT,請按照 ASP.NET 部落格提供的安裝說明進行操作。
預覽版 4 包括適用於 iOS、Android、tvOS、MacOS 和 MacCatalyst 的 .NET MAUI 工作負載。
請注意,dotnet 工作負載安裝會將工作負載從 NuGet.org 複製到您的 SDK 安裝中,因此如果 SDK 安裝位置受到保護(意味著在管理員/根位置),則需要運行提升 /sudo。
內置SDK版本檢查
為了更輕鬆地跟蹤新版本的 SDK 和運行時何時可用,我們向 .NET 6 SDK 添加了一個新命令:dotnet sdk check
這將告訴您在每個功能帶內什麼是 .NET SDK 和 .NET 運行時的最新可用版本。
CLI 模板 (dotnet new)
預覽版 4 引入了新的模板搜索功能。 dotnet new –search 將在 NuGet.org
中搜索匹配模板。在即將進行的預覽期間,用於此搜索的數據將更頻繁地更新。
CLI 中安裝的模板可用於 CLI 和 Visual Studio。安裝新版本 SDK 時用戶安裝的模板丟失的早期問題已得到解決,但是需要重新安裝 .NET 6 Preview 4 之前安裝的模板。
模板安裝的其他改進包括支援 –interactive 開關以支援私有 NuGet 源的授權憑據。
安裝 CLI 模板後,您可以通過 –update-check 和 –update-apply 檢查更新是否可用。這現在將更快地反映模板更新,支援您定義的 NuGet 源,並支援 –interactive 授權憑據。
在預覽版 4 和即將發布的預覽版中,將清理 dotnet new 命令的輸出,以專註於您最需要的資訊。例如, dotnet new –install
為了支援這些以及即將對 dotnet new 進行的更改,我們正在對模板引擎 API 進行重大更改,這可能會影響託管模板引擎的任何人。這些更改將出現在預覽版 4 和預覽版 5 中。如果您託管模板引擎,請通過//github.com/dotnet/templating與我們聯繫,以便我們與您合作以避免或最大限度地減少中斷。
支援
.NET 6 將於 2021 年 11 月發布,並將作為長期支援 (LTS) 版本提供三年支援。平台矩陣已顯著擴展。
新增內容是:
-
Android
-
IOS
-
Mac 和 Mac Catalyst,適用於 x64 和 Apple Silicon(又名”M1″)
-
Windows Arm64(特別是 Windows 桌面)
.NET 6 Debian 容器映像基於 Debian 11(”bullseye”),目前正在測試中。
結束
此時我們已經進入 .NET 6 版本。 雖然 11 月的最終版本似乎還有很長的路要走,但我們已接近完成功能開發。現在是回饋的好時機,因為新功能的形狀現在已經確定,而且我們仍處於積極的開發階段,因此可以很容易地根據回饋採取行動。
說到 11 月,請在 11 月 9 日至 11 日期間預訂一些時間觀看 .NET Conf 2021。這肯定會令人興奮和有趣。 我們將在 11月 9 日發布最終的 .NET 6 版本,以及比這一篇更長的博文。
還在尋找更多閱讀?您可以查看我們的新對話系列。有很多關於 .NET 6 新功能的詳細見解。有任何技術問題,請在Microsoft Q&A 上提問.
我們希望您喜歡試用預覽版 4。