我们很高兴地宣布,F# 6已经上市,与.NET 6 RC2和Visual Studio 2022 RC2一起发货。这是使你更容易编写健壮、简洁和高性能代码的下一步。你可以通过以下方式获得F# 6:
F# 6是为了让F#更简单、更有性能。这适用于语言设计、库和工具。长期语言演进的一个主要目标是消除语言中令用户惊讶或在采用过程中不必要的障碍的角落。我们很高兴在这个版本中与F#社区合作,使F#语言更简单、性能更强、更容易学习。
要了解更多关于F#的信息,请参见The .NET Conf Focus Day on F#including theF# Bonanza,Guido van Rossum Learns F#andStarting Your F# Journey.
让F#更快,与任务{...}更具互操作性
F#要求最多的功能之一--也是这个版本中最重要的技术特征--是使编写异步任务更简单、性能更强,并与C#等其他.NET语言更具有互操作性。以前,创建.NET任务需要使用async {…} 来创建一个任务,然后用Async.AwaitTask 来调用它。现在有了F# 6,你可以直接使用task {…} 来创建任务并等待它。例如,考虑以下F#代码来创建一个与.NET兼容的任务:
let readFilesTask (path1, path2) =
async {
let! bytes1 = File.ReadAllBytesAsync(path1) |> Async.AwaitTask
let! bytes2 = File.ReadAllBytesAsync(path2) |> Async.AwaitTask
return Array.append bytes1 bytes2
} |> Async.StartAsTask
这段代码现在可以变成:
let readFilesTask (path1, path2) =
task {
let! bytes1 = File.ReadAllBytesAsync(path1)
let! bytes2 = File.ReadAllBytesAsync(path2)
return Array.append bytes1 bytes2
}
在F#代码中,对task {…} 的内置支持是无处不在的--不需要打开命名空间。
任务支持之前已经通过优秀的TaskBuilder.fs和Ply库提供给F# 5.0。这些指导了F# 6中的支持设计,并提供了重要的测试来源。这些库的作者直接或间接地对F# 6的设计做出了重大贡献。将代码迁移到内置支持上应该是很简单的。不过也有一些区别:命名空间和类型推理在内置支持和这些库之间略有不同,而且可能需要一些额外的类型注释。如果明确引用了这些库,并且在每个文件中打开了正确的命名空间,那么这些社区库仍然可以在F# 6中使用。
使用task {…} 与async {…} 非常相似,两者都支持。与async {…} 相比,使用task {…} 有几个优点:
task {…}的性能要好得多。task {…}的调试步骤和堆栈跟踪更好。- 与期望或产生任务的.NET包的互操作更容易。
如果你熟悉async {…} ,有一些区别需要注意:
task {…}立即执行任务到第一个异步产量。task {…}不隐含地传播一个取消标记。task {…}不执行隐式取消检查。task {…}不支持异步tailcalls。这意味着如果没有中间的异步产生,递归地使用 可能会导致堆栈溢出。return! ..
一般来说,如果与使用任务的.NET库互操作,你应该考虑在新代码中使用task {…} 而不是async {…} 。在切换到task {…} 之前,请审查代码,以确保你不依赖于async {…} 的上述特性。
F# 6的task {…} 支持是建立在一个叫做 "可恢复代码 "RFC FS-1087的基础上的。可恢复代码是一个核心技术特征,它可以用来构建许多种高性能的异步和收益状态机。
在未来几个月里,我们将与F#社区合作,利用这一特性,提供两个关键的可选软件包:
- 使用可恢复代码对F#
async {…}的快速重新实现。 - 一个使用可恢复代码的异步序列的快速重新实现
asyncSeq {…}。
最初,这些将通过FSharp.Control.AsyncSeq等社区包提供。在未来的版本中,它们可能被集成到FSharp.Core中。
让F#更简单易学:用expr[idx]进行索引
在F# 6中,我们开始允许索引语法的语法expr[idx] 。
到F# 5.0为止,包括F# 5.0,F#一直使用expr.[idx] 作为索引语法。这种语法是基于OCaml中用于字符串索引查找的类似符号。允许使用expr[idx] ,是基于那些学习F#或第一次看到F#的人的反复反馈,即使用点符号索引是对标准行业实践的不必要的背离。F#没有必要在这里偏离。
这不是一个突破性的变化--默认情况下,使用expr.[idx] ,不会发出任何警告。然而,一些与此相关的信息被发出,建议对代码进行澄清,一些进一步的信息可以被选择性地激活。例如,可以激活一个可选的信息警告(/warnon:3566 ),以开始报告对expr.[idx] 符号的使用。详见索引器标记法。
在新代码中,我们建议系统地使用expr[idx] 作为索引语法。
让F#更快。部分活动模式的结构表示
F#包括活动模式功能,允许用户以直观和强大的方式扩展模式匹配。在F# 6中,我们用活动模式的可选Struct表示法增强了该功能。这允许你使用一个属性来约束部分活动模式,使其返回一个值选项:
[<return: Struct>]
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| true, int -> ValueSome(int)
| _ -> ValueNone
该属性的使用是必须的。在使用时,代码并没有改变。最后结果是,分配被减少了。
让F#更加统一:计算表达式中的重载自定义操作
F# 6激活了 "计算表达式中的重载自定义操作 "功能,该功能从F# 5.0开始就处于预览状态。这使得F#中的DSL更加简单,包括用于验证和网络编程。
该功能之前在F# 5.0预览版的公告中有所描述,并实现了F# RFC 1056。
使F#更加统一——"as "模式
在F# 6中,"as "模式的右侧现在也可以是一个模式。当一个类型测试给了一个输入更强的类型时,这一点很重要。例如,请考虑以下代码:
type Pair = Pair of int * int
let analyzeObject (input: obj) =
match input with
| :? (int * int) as (x, y) -> printfn $"A tuple: {x}, {y}"
| :? Pair as Pair (x, y) -> printfn $"A DU: {x}, {y}"
| _ -> printfn "Nope"
let input = box (1, 2)
在每个模式的情况下,输入对象都经过了类型测试。"as "模式的右侧现在被允许成为一个进一步的模式,它本身可以匹配更强类型的对象。
使得F#更加统一——缩进语法的修订
F#社区做出了一些重要的改进,使F#语言在F# 6中更加统一。其中最重要的是消除了F#在使用缩进感知语法方面的一些不一致和限制,见RFC FS-1108。这解决了F#用户自F# 4.0以来所强调的10个重大问题。
例如,在F# 5.0中,允许使用:
let c = (
printfn "aaaa"
printfn "bbbb"
)
但是下面的内容不允许(产生一个警告):
let c = [
1
2
]
在F# 6中,两者都是允许的。这使得F#更简单,更容易学习。F#社区的贡献者Hadrian Tang在这方面起到了带头作用,包括对该功能进行了出色的、非常有价值的系统测试。
使F#更加统一——使用绑定时的丢弃
F# 6允许_ ,例如,在use 绑定中使用:
let doSomething () =
use _ = System.IO.File.OpenText("input.txt")
printfn "reading the file"
这一特性实现了F# RFC FS-1102。
使F#更加统一——二进制数字的格式化
F# 6将%B 模式添加到二进制数字格式的可用格式指定器中。考虑一下下面的F#代码。
printf "%o" 123
printf "%B" 123
这段代码打印出以下输出:
173
1111011
这一特性实现了F# RFC FS-1100。
让F#更快。InlineIfLambda
在F# 6中,我们增加了一个新的声明性功能,允许代码选择性地表明lambda参数应该在调用处被内联。
例如,考虑下面这个iterate 函数来遍历一个数组:
let inline iterateTwice ([<InlineIfLambda>] action) (array: 'T[]) =
for j = 0 to array.Length-1 do
action array[j]
for j = 0 to array.Length-1 do
action array[j]
如果调用点是:
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
那么经过内联和其他优化,代码就变成了:
let arr = [| 1.. 100 |]
let mutable sum = 0
for j = 0 to array.Length-1 do
sum <- array[i] + x
for j = 0 to array.Length-1 do
sum <- array[i] + x
与以前的F#版本不同的是,无论涉及到的lambda表达式的大小,这种优化都适用。这个特性也可以用来可靠地实现循环解卷和类似的转换。
可以打开一个选择警告(/warnon:3517 ,默认为关闭),以指示你的代码中InlineIfLambda 参数在调用处没有绑定到lambda表达式的地方。在正常情况下,这个警告不应该被启用,但是在某些高性能编程中,它对于确保所有代码被内联和扁平化是很有用的。
让F#更快。改进列表和数组表达式的性能和调试
在F# 6中,生成式列表和数组表达式的编译形式现在快了4倍(见相关的拉动请求)。生成式列表和数组表达式的调试也有了很大的改进。比如说:
let generateList (i: int) =
[ "a"
"b"
for j in 1 .. 10 do
"c"
if i % 3 = 0 then
"d"
"e"
]
这个函数根据输入生成大小为13或23的列表,现在执行起来更有效率,而且可以在各个行上设置断点。
使得F#更简单,更具有互操作性。隐式转换
在F# 6中,我们激活了对F#中额外的 "隐式 "和 "类型定向 "转换的支持,如RFC FS-1093中所述。
这一变化实现了三件事:
- 需要更少的显式上报
- 需要更少的显式整数转换
- 增加了对.NET风格的隐式转换的一流支持
额外的隐式上播转换
在F# 5.0及以前的版本中,当实现一个函数时,如果表达式在不同的分支上有不同的子类型,即使有类型注解,也需要对返回表达式进行上报。考虑一下下面的F# 5.0代码(StreamReader派生自TextReader):
open System
open System.IO
let findInputSource() : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt") :> TextReader
在这里,条件的分支分别计算TextReader和StreamReader,并添加了上播以使两个分支都具有TextReader类型。在F# 6中,这些upcasts现在被自动添加。这意味着现在的代码可以更简单:
let findInputSource() : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt")
你可以选择启用警告/warnon:3388 ,以便在每一次使用额外的隐式upcast时显示一个警告,如下所述。
隐式整数转换
类型导向的转换也允许更经常地将32位整数自动拓宽为64位整数。例如,64位整数的使用现在在机器学习库中是无处不在的。考虑一个典型的API形状:
type Tensor(…) =
static member Create(sizes: seq<int64>) = Tensor(…)
在F# 5.0中,必须使用int64的整数字面:
Tensor.Create([100L; 10L; 10L])
或
Tensor.Create([int64 100; int64 10; int64 10])
在F# 6中,当类型推理过程中源和目的类型都是已知的,int32 到int64 ,int32 到nativeint 和int32 到double ,加宽会自动发生,所以在上述int32 字面的情况下可以使用:
Tensor.Create([100; 10; 10])
尽管有这样的变化,F#仍然在大多数情况下继续使用数字类型的显式加宽。例如,隐式加宽不适用于其他数字类型,如int8 或int16 ,也不适用于从float32 到float64 ,更不适用于源或目的类型未知的情况。你也可以选择启用警告/warnon:3389,在每个op_Implicit被用于方法参数的时候显示警告。
注意:高性能的现代张量实现可以通过TorchSharp和TensorFlow.NET获得。
对.NET风格的隐式转换的一流支持
增加的类型定向转换允许.NET "op_Implicit "转换在F#代码中调用方法时自动应用。例如,在F# 5.0中,当与XML的.NET APIs一起工作时,有必要使用XName.op_Implicit :
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")
在F# 6中,当参数表达式可用且类型为源表达式和目标类型已知时,op_Implicit 转换会被自动应用:
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")
你可以选择启用警告/warnon:3390 ,在每一个使用隐式数字加宽的点上显示一个警告,如下所述。
隐式转换的可选警告
当广泛使用或不适当地使用时,类型定向和隐式转换会与类型推理互动不良,导致代码更难理解。由于这个原因,一些缓解措施已经到位,以帮助确保这一特性不会在F#代码中被广泛滥用。首先,源类型和目的类型都必须是众所周知的,不能有歧义或产生额外的类型推理。其次,可以激活选择警告来报告任何隐式转换的使用,默认情况下有一个警告:
/warnon:3388(额外的隐式上播)/warnon:3389(隐式数字加宽)/warnon:3390(op_Implicit at method arguments)/warnon:3391(op_Implicit at non-method arguments, on by default)
如果你的团队想禁止所有隐式转换的使用,你也可以使用/warnaserror:3388,/warnaserror:3389,/warnaserror:3390,/warnaserror:3391 。
让F#更简单:更新不可变的集合
这个版本在FSharp.Core的核心集合函数中增加了五个新的操作。它们是:
- List/Array/Seq.insertAt
- List/Array/Seq.removeAt
- List/Array/Seq.updateAt
- List/Array/Seq.insertManyAt
- List/Array/Seq.removeManyAt
这些都是在相应的集合类型或序列上执行复制和更新操作。使用这些函数的例子可以在文档中看到,例如List.insertAt。
作为一个例子,考虑一下以Elmish风格编写的一个简单的 "Todo List "应用程序的模型、消息和更新逻辑。在这里,用户与应用程序进行交互,产生消息,update 函数处理这些消息,产生一个新的模型:
type Model =
{ ToDo: string list }
type Message =
| InsertToDo of index: int * what: string
| RemoveToDo of index: int
| LoadedToDos of index: int * what: string list
let update (model: Model) (message: Message) =
match message with
| InsertToDo (index, what) ->
{ model with ToDo = model.ToDo |> List.insertAt index what }
| RemoveToDo index ->
{ model with ToDo = model.ToDo |> List.removeAt index }
| LoadedToDos (index, what) ->
{ model with ToDo = model.ToDo |> List.insertManyAt index what }
有了这些新的函数,逻辑清晰简单,只依赖不可变的数据。
让F#更简单:Map有键和值
在FSharp.Core 6.0.0.0中,Map 类型new支持Keys和Value属性。这些并不复制底层集合。
让F#更简单:NativePtr的额外本征
在FSharp.Core 6.0.0.0中,我们为NativePtr模块添加了新的内在因素:
NativePtr.nullPtrNativePtr.isNullPtrNativePtr.initBlockNativePtr.clearNativePtr.copyNativePtr.copyBlockNativePtr.ofILSigPtrNativePtr.toILSigPtr
与NativePtr 中的其他函数一样,这些函数是内联的,除非使用/nowarn:9 ,否则使用它们会发出警告。这些函数的使用被限制在非管理类型上。
使F#更加统一——带有单位注解的额外数字类型
F#支持计量单位,允许在数字类型中添加注释标签。然而,在以前的版本中,并非所有的数字类型都支持这些注释。在F# 6中,以下类型或类型缩写别名现在支持计量单位注释,新增加的类型用+表示。
| F#别名 | CLR类型 |
|---|---|
float32/single++ | System.Single |
float/double+ | System.Double |
decimal | System.Decimal |
sbyte/int8+ | System.SByte |
int16 | System.Int16 |
int/int32+ | System.Int32 |
int64 | System.Int64 |
byte+/uint8+ | System.Byte |
uint16+ | System.UInt16 |
uint+/uint32+ | System.UInt32 |
uint64+ | System.UIn64 |
nativeint+ | System.IntPtr |
unativeint+ | System.UIntPtr |
例如,你可以对一个无符号整数进行如下注释。
[<Measure>]
type days
let better_age = 3u<days>
这一设计修订是由社区成员Paulmichael Blasucci倡导、设计和实施的。
将F#向前推进。减少很少使用的符号操作符的使用
在F#编程中,"ref单元 "可用于堆分配的可变寄存器。虽然它们偶尔很有用,但在现代F#编码中很少需要这些,因为通常可以用let mutable 。F#核心库包括两个运算符:= 和! 以及两个函数incr 和decr ,专门与引用调用相关。这些操作符的存在使得引用单元在F#编程中的地位更加重要,要求所有的F#程序员都知道这些操作符。此外,! 操作符很容易与C#和其他语言中的not 操作相混淆,这在翻译代码时是一个潜在的微妙的错误来源。
因此,在F# 6中,我们决定给出软性指导,在F# 6及以后的版本中,对:= 、! 、incr 和decr 的使用进行去规范化。使用这些操作符和函数现在会给出信息,要求你用明确使用Value 属性来替换你的代码。
这一变化的理由是为了减少F#程序员需要知道的运算符的数量。
例如,考虑下面的F# 5.0代码:
let r = ref 0
let doSomething() =
printfn "doing something"
r := !r + 1
首先,在现代F#编码中,很少需要引用单元格,因为通常可以使用`let mutable:
let mutable r = 0
let doSomething() =
printfn "doing something"
r <- r + 1
如果使用了引用单元格,那么在F# 6中会发出一个信息警告,要求你将最后一行改为r.Value <- r.Value + 1 ,并将你链接到关于适当使用引用单元格的进一步指导。
let r = ref 0
let doSomething() =
printfn "doing something”"
r.Value <- r.Value + 1
这些信息不是警告--它们是显示在IDE中的 "信息性信息"。这仍然是向后兼容的,并在RFC FS-1111中有所描述。
使F#向前发展——删除长期废弃的遗留功能
F# 2.0废弃了几个F#特性,如果使用这些特性,会发出警告。这些特性在F# 6.0中被删除了,并且会出现错误,除非你明确使用/langversion:5.0 或之前。现在出现错误的特性是。
- 多个通用参数使用后缀类型名称,例如
(int, int) Dictionary。这在F# 6中成为一个错误,应该使用标准的Dictionary<int,int>来代替。 #indent "off".这在F# 6中成为一个错误x.(expr).这在F# 6中成为一个错误。module M = struct … end.这成为F# 6中的一个错误。- 使用输入
*.ml和*.mli。这将成为F# 6中的一个错误。 - 使用
(*IF-CAML*)或(*IF-OCAML*)。这将成为F# 6中的一个错误。 - 使用
land,lor,lxor,lsl,lsr或asr作为infix运算符。这些在F#中是infix关键字,因为它们在OCaml中是infix关键字,在FSharp.Core中没有定义。现在使用这些关键字会发出警告(而不是错误)。
这些在RFC FS-1114中有描述
F#工具——管道调试!
F# 6工具链中最令人期待的功能之一是增加了 "管道调试"。现在,F#编译器为F#管道中涉及|>、||>和||>操作符的每个位置发出调试步进点。在每一步,管道的输入或中间阶段可以在一个典型的调试器中被检查。
比如说:

也可以在流水线的每个点设置断点,例如:。

当你用F# 6编译器重新编译你的代码时,不管你使用的是什么语言版本或IDE,管道调试都会默认激活。玩玩步进和断点,让我们知道你的想法!
F#工具——调试器中显示值的阴影
更新后的F# 6工具链对调试进行了另一项重要改进。例如,请考虑以下代码
let someFunctionUsingShadowing x =
let yyy = "aa"
let yyy = "aa".Length - 1
yyy + 3
这里第二个yyy "影射 "第一个。这在F#中是允许的,而且这种技术是一种常见的技术,因为F#默认为不可变的绑定,因此新版本的绑定经常取代以前的绑定。
当使用F# 6工具链时,与locals相关的名称会在发生阴影的作用域的那些部分进行调整。例如,当把断点放在上述函数的表达式yyy + 3 ,locals就会显示如下。

F#工具——性能和可扩展性
在F# 6中,我们在语言的核心实现和Visual Studio组件中对编译器/IDE-tooling的perf/scalability进行了巨大的改进:
- F#编译器现在以并行方式执行解析阶段,从而使大型项目的性能提高了约5%。
- 分析结果现在是同步进行的。在IDE中工作时,分析请求不再通过单一的 "反应器 "编译线程进行序列化。相反,F#编译器服务现在是并发的。这大大提高了许多情况下的性能。
- 改进了包含签名文件的F#项目中的分析性能。如果你在项目中使用签名文件,当对实现文件进行修改而不改变签名文件时,你会更快地看到诊断和其他分析结果。这一变化也包含在Visual Studio 2019的最终版本中。
- 查找所有引用现在是在多个项目中并行执行的。
- 对 "关闭解决方案 "和 "切换配置 "进行了重大性能改进。例如,一些简单的用例将 "关闭解决方案 "从16秒减少到1秒。关于这方面的演示,请看贡献者Will Smith的这条推文。
F#工具。内存中的跨项目引用!
在F# 6中,我们通过从F#到C#的 "内存跨项目引用 "使F#和C#项目之间的工作更加简单和可靠。
这意味着C#项目现在可以立即反映在F#项目中,而不必在磁盘上编译C#项目。这也意味着分析结果可以在未编译的解决方案中使用。
F#工具:.NET Core是脚本的默认版本
如果你在Visual Studio中打开或执行一个F#脚本(.fsx ),默认情况下,该脚本将使用64位执行的.NET Core进行分析和执行。这一功能在Visual Studio 2019中处于预览状态,现在默认启用。
要启用.NET框架脚本,请使用Tools -> Options -> F# Tools -> F# Interactive ,并将Use .NET Core Scripting 设置为false ,然后重新启动F#互动窗口。这一设置同时影响到脚本编辑和脚本执行。
64位脚本现在也是默认的。要启用.NET框架脚本的32位执行,也要将64-bit F# Interactive 设为false 。.NET核心脚本没有32位选项。
F#工具——F# 脚本现在尊重 global.json
如果你在一个包含有.NET SDK设置的global.json 的目录中使用dotnet fsi 执行一个脚本,那么所列出的.NET SDK版本将被用来执行和编辑该脚本。这个功能已经在后来的.NET 5版本中进行了预览。
例如,假设一个脚本在一个目录中,有以下global.json ,指定了一个.NET SDK版本策略。
{
"sdk": {
"version": "5.0.200",
"rollForward": "minor"
}
}
这是一个强大的功能,可以让你 "锁定 "用于编译、分析和执行脚本的SDK:
- 如果你现在使用
dotnet fsi,从这个目录中执行脚本,SDK的版本将被尊重。如果没有找到SDK,你可能需要在你的开发机器上安装它。 - 当你编辑脚本时,Visual Studio和其他IDE会尊重这个设置。
- 当你在Visual Studio中启动或重置F#交互式评估窗口时,SDK的选择会被延迟,直到你第一次从脚本中使用 "发送到交互式"(Alt-Enter)。这时,所选择的SDK将是用于编辑和执行脚本的SDK。
在Linux和其他UNIX系统上,你可以将global.json 与语言版本的shebang结合起来,以直接执行脚本。一个用于script.fsx 的简单shebang是:
#!/usr/bin/env -S dotnet fsi
printfn "Hello, world"
脚本可以用script.fsx 直接执行。 你可以像这样把它和一个特定的、非默认的语言版本结合起来:
#!/usr/bin/env -S dotnet fsi --langversion:5.0
注意,这个设置会被编辑工具所忽略,它们会假设最新的语言版本来分析脚本。
F#工具:Visual Studio Code和Visual Studio中的.NET交互式!
.NET交互式笔记本允许你使用F#和C#的笔记本式编程。在最近的版本中进行了许多改进,包括在Visual Studio Code中的出色支持。
另外刚刚宣布的是Visual Studio 2022的笔记本编辑器扩展。
让F#更加简单易学——代码实例!
10月,F#社区开展了一项活动,为F#核心库的所有公共入口添加代码实例。现在已经有800个代码实例被贡献出来!比如说。
- List、Array、Seq和Map模块中的所有函数现在都有代码实例。
- 高级模块(如Quotations)中的函数和方法现在都有例子。
你可以通过这个GitHub问题为这个倡议做出贡献。
System.Text.Json对常见F#类型的支持
从.NET 6开始,System.Text.Json将内置对常见F#类型的支持。下面是一个例子:
目前还不支持用户定义的歧视性联合体。感谢Eirik Tsarpalis对.NET的贡献。
.NET 6的一般改进
F# 6是建立在.NET 6之上的,F#程序员可以直接或间接地从运行时的一系列新功能和改进中受益。下面列出了其中的一些,是从.NET 6 Release Candidate 1的公告和以前的发布公告中总结出来的:
- 源码构建,一个正在与红帽开发的方案和基础设施,旨在满足常用的Linux发行版,如Debian和Fedora的打包规则。同时,源码构建的目的是使.NET核心的贡献者能够在多个存储库中以协调的变化构建.NET核心SDK。该技术旨在解决开发者在试图从源码构建整个.NET Core SDK时遇到的常见挑战。
- 配置文件引导的优化,它基于这样的假设:作为启动的一部分执行的代码往往是统一的,通过利用它可以提供更高水平的性能。PGO可以以更高的质量编译启动代码,减少二进制文件的大小,并重新安排应用程序的二进制文件,以便在启动时使用的代码在文件的开始附近共同定位。
- 动态PGO,是PGO的镜像,与RyuJIT .NET即时编译器集成。性能得到了改善。
- Crossgen2,通过提前编译生成和优化代码,现在在发布ReadyToRun图像时默认启用。
- 英特尔控制执行技术(CET),在一些新的英特尔和AMD处理器中可用,以防止涉及控制流劫持的常见攻击类型。
- HTTP/3,在.NET 6中预览,解决了以前版本的HTTP的功能和性能挑战。
- W^X是一种安全缓解措施,通过不允许内存页同时可写和可执行来阻止攻击路径。
.NET 6的其他改进包括:
- 接口铸造性能提高了16%,达到38%。
- 在RyuJIT中,代码生成已经通过多种变化得到了改进,使过程更加有效,或使产生的代码运行更快。
- 单一文件包现在支持压缩。
- 单一文件应用程序发布的改进,包括改进分析以允许自定义警告。
- 增强的日期、时间和时区支持。
- 大大改善了Windows上的FileStream性能。
- 为Linux上的密码学增加了OpenSSL 3支持。
- 增加了对OpenTelemetry Metrics API的支持。OpenTelemetry在最近的.NET版本中得到了支持,它促进了观察能力。
- 用于库的WebSocket压缩减少了在网络上传输的数据量。
- 包验证工具使NuGet库开发者能够验证包是一致的和格式良好的。
- DirectoryServices.Protocols的TLS支持。
- 本地内存分配API。
Visual Studio中的一般改进
F# 6的发布与Windows上的Visual Studio 2022的发布相吻合。使用这种IDE经验的F#程序员将从这个版本的许多改进中受益:
- Windows上的Visual Studio 2022现在是一个64位的应用程序。这意味着你可以打开、编辑、运行和调试即使是最大和最复杂的解决方案,而不会耗尽内存。
- 在文件中查找的速度更快。在搜索大型解决方案(如Orchard Core)时,在文件中查找的速度现在提高了3倍。
- 在IDE中支持Git的多发布。如果你曾与托管在不同Git仓库的项目合作,你可能会使用外部工具或Visual Studio的多个实例来连接它们。有了Visual Studio 2022,你可以在一个拥有多个仓库的项目的单一解决方案中工作,并从一个Visual Studio实例中对它们做出贡献。
- 个性化改进。例如,Visual Studio 2022为你提供了与你的Windows主题同步的能力--如果你在那里启用了 "夜光 "功能,Visual Studio也会使用它。
下一步是什么
现在,F# 6已经发布,我们正在将注意力转移到几个方面:
- 简化F#的学习体验
- 继续使F#语言服务的实现现代化
- 为下一个F#版本做计划
感谢和致谢!
F#是由.NET基金会、F#软件基金会、其成员和包括微软在内的其他贡献者合作开发的。F#社区参与了创新、设计、实施和交付的各个阶段,我们很自豪能成为这个社区的贡献者。
