我們很高興釋出 .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 是隨 .NET Core 3.0 和 C# 8 新增的一項重要功能。新的增強功能支援使用IAsyncEnumerable 物件進行 System.Text.Json(反)序列化。
以下示例使用流作為任何非同步資料來源的表示。源可以是本地機器上的檔案,也可以是資料庫查詢或 Web 服務 API 呼叫的結果。
流序列化
System.Text.Json 現在支援將 IAsyncEnumerable 值序列化為 JSON 陣列,如下例所示。
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 的新 API。 我們為此添加了 JsonSerializer.DeserializeAsyncEnumerable 方法,如下例所示。
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 的源或利用 Linq 採用的一些內部優化。
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 時的隱式轉換 (https://github.com/dotnet/runtime/pull/49412)
通過 TimeZoneInfo 上的新 API 進行顯式轉換:TryConvertIanaIdToWindowsId、TryConvertWindowsIdToIanaId
和 HasIanaId (https://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 作為引數的新建構函式。(https://github.com/dotnet/runtime/issues/50256
TimeZoneInfo.AdjustmentRule 還獲得了在 Unix 上載入時區的其他修復(https://github.com/dotnet/runtime/pull/49733),(https://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 桌面框架)的大部分進行了註釋,以便它們生成準確的剪裁警告。因此,我們認為是時候預設啟用剪裁警告了。
您可以通過將 設定為 true 來禁用警告。對於早期版本,您可以將相同的屬性設定為 false 以檢視剪裁警告。
剪裁警告為剪裁過程帶來了可預測性,並使開發人員掌握了權力。我們將繼續註釋更多 .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 中。如果您託管模板引擎,請通過https://github.com/dotnet/templating與我們聯絡,以便我們與您合作以避免或最大限度地減少中斷。
支援
.NET 6 將於 2021 年 11 月釋出,並將作為長期支援 (LTS) 版本提供三年支援。平臺矩陣已顯著擴充套件。
新增內容是:
安卓
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。