ASP.NET Core 6 的性能改进

受到 由Stephen Toub 发布的关于 .NET 性能的博客的启发,我们正在写一篇类似的文章来强调ASP.NET Core 在6.0 中所做的性能改进。

基准设置

我们整个过程中大部分的实例使用的是BenchmarkDotNet。在此链接上提供了repo,其中包括本文中使用的大多数基准。

BenchmarkDotNet

https://github.com/dotnet/benchmarkdotnet

在此链接

https://github.com/BrennanConroy/BlogPost60Bench

本文中的大多数基准测试结果都是通过以下命令行生成的:

然后从列表中选择要运行的特定基准。

这命令行给BenchmarkDotNet指令:

  • 在发布配置中构建所有内容。

  • 针对 .NET Framework 4.8 外围区域构建它。

  • 在 .NET Framework 4.8、.NET Core 3.1、.NET 5 和 .NET 6 上运行每个基准测试。

  • 对于某些基准测试,它们仅在 .NET 6 上运行(例如,如果比较同一版本上的编码的两种方式):

dotnet run -c Release -f net6.0 --runtimes net6.0

对于其他人,只运行了版本的一个子集,例如

dotnet run -c Release -f net5.0 --runtimes net5.0 net6.0

我将包括用于运行每个基准测试的命令。

本文中的大多数结果都是在Windows上运行上述基准测试生成的,主要是为了将. NET Framework 4.8包含在结果集中。但是,除非另有说明,一般来说,所有这些基准测试在Linux或macOS上运行时都显示出相当显著的改进。只需确保您已经安装了想要测量的每个运行时。这些基准测试使用的是.NET 6 RC1的构建,以及最新发布的.NET 5和.NET Core 3.1下载。

.NET 6 RC1的构建

https://github.com/dotnet/installer/blob/main/README.md#installers-and-binaries

最新发布

https://dotnet.microsoft.com/en-us/download

span< T >

自从在.NET 2.1中增加了Span<T>,之后的每一个版本我们都转换了更多的代码以在内部和作为公共API的一部分使用Span来提高性能。这次发布也不例外。

PR dotnet/aspnetcore#28855 在添加两个 PathString 实例时删除了来自 string.SubString的 PathString 中的临时字符串分配,而是使用 Span作为临时字符串。在下面的基准测试中,我们使用一个短字符串和一个长字符串来显示避免使用临时字符串的性能差异。

dotnet run -c Release -f net48 --runtimes net48 net5.0 net6.0 --filter *PathStringBenchmark*private PathString _first = new PathString("/first/");
private PathString _second = new PathString("/second/");
private PathString _long = new PathString("/longerpathstringtoshowsubstring/");[Benchmark]
public PathString AddShortString()
{return _first.Add(_second);
}[Benchmark]
public PathString AddLongString()
{return _first.Add(_long);
}

38cea547e9b87c312a055c93b0b9bd0d.png

dotnet/aspnetcore#34001引入了一个新的基于Span的API,用于枚举查询字符串,在没有编码字符的常见情况下,该查询字符串是分配空闲的,当查询字符串包含编码字符时,分配更低。

dotnet run -c Release -f net6.0 --runtimes net6.0 --filter *QueryEnumerableBenchmark*#if NET6_0_OR_GREATERpublic enum QueryEnum{Simple = 1,Encoded,}[ParamsAllValues]public QueryEnum QueryParam { get; set; }private string SimpleQueryString = "?key1=value1&key2=value2";private string QueryStringWithEncoding = "?key1=valu%20&key2=value%20";[Benchmark(Baseline  = true)]public void QueryHelper(){var queryString = QueryParam == QueryEnum.Simple ? SimpleQueryString : QueryStringWithEncoding;foreach (var queryParam in QueryHelpers.ParseQuery(queryString)){_ = queryParam.Key;_ = queryParam.Value;}}[Benchmark]public void QueryEnumerable(){var queryString = QueryParam == QueryEnum.Simple ? SimpleQueryString : QueryStringWithEncoding;foreach (var queryParam in new QueryStringEnumerable(queryString)){_ = queryParam.DecodeName();_ = queryParam.DecodeValue();}}
#endif

d36ae0df474104389dc43fd020ddcdff.png

需要注意的是,天下没有免费的午餐。在新的QueryStringEnumerable API的情况下,如果您计划多次枚举查询字符串值,它实际上可能比使用 QueryHelpers.ParseQuery 并存储已解析查询字符串值的字典更昂贵。

@paulomorgado 的 dotnet/aspnetcore#29448 使用 string.Create 方法,如果您知道字符串的最终大小,则该方法允许在创建字符串后对其进行初始化。这是用来移除UriHelper.BuildAbsolute中的一些临时字符串分配。

dotnet run -c Release -f netcoreapp3.1 --runtimes netcoreapp3.1 net6.0 --filter *UriHelperBenchmark*#if NETCOREAPP[Benchmark]public void BuildAbsolute(){_ = UriHelper.BuildAbsolute("https", new HostString("localhost"));}
#endif

699b79d168ec7839d77d978407124a53.png

PR dotnet/aspnetcore#31267将 ContentDispositionHeaderValue 中的一些解析逻辑转换为使用基于 Span<T> 的 API,以避免在常见情况下出现临时字符串和临时 byte[]。

dotnet run -c Release -f net48 --runtimes net48 netcoreapp3.1 net5.0 net6.0 --filter *ContentDispositionBenchmark*
[Benchmark]
public void ParseContentDispositionHeader()
{var contentDisposition = new ContentDispositionHeaderValue("inline");contentDisposition.FileName = "FileÃName.bat";}

c8f7cc5ac5f5d72aa3adc409a183058a.png

dotnet/aspnetcore#28855 

https://github.com/dotnet/aspnetcore/pull/28855

dotnet/aspnetcore#34001

https://github.com/dotnet/aspnetcore/pull/34001

天下没有免费的午餐

https://en.wikipedia.org/wiki/There_ain%27t_no_such_thing_as_a_free_lunch

paulomorgado

https://github.com/paulomorgado

dotnet/aspnetcore#29448

https://github.com/dotnet/aspnetcore/pull/29448

string.Create

https://docs.microsoft.com/en-us/dotnet/api/system.string.create?view=net-6.0

空闲连接

ASP.NET Core 的主要组件之一是托管服务器,它带来了许多不同的问题需要去优化。我们将重点关注6.0中空闲连接的改进,在其中我们做了许多更改,以减少连接等待数据时所使用的内存量。

我们进行了三种不同类型的更改,一种是减少连接使用的对象的大小,这包括System.IO.Pipelines、SocketConnections 和 SocketSenders。第二种类型的更改是将常用访问的对象池化,这样我们就可以重用旧实例并节省分配。第三种类型的改变是利用所谓的“零字节读取”。在这里,我们尝试用一个零字节缓冲区从连接中读取数据,如果有可用的数据,,读取将返回没有数据,但我们知道现在有可用的数据,可以提供一个缓冲区来立即读取该数据。这避免了为将来可能完成的读取预先分配一个缓冲区,所以在知道数据可用之前,我们可以避免大量的分配。

dotnet/runtime#49270将 System.IO.Pipelines 的大小从 ~560 字节减少到 ~368 字节,减少了34%,每个连接至少有2个管道,所以这是一个巨大的胜利。

dotnet/aspnetcore#31308重构了Kestrel的Socket层,以避免一些异步状态机,并减少剩余状态机的大小,从而为每个连接节省33%的分配。

dotnet/aspnetcore#30769删除了每个连接的PipeOptions分配,并将该分配移动到连接工厂,因此我们只分配一个服务器的整个生命周期,并为每个连接重用相同的选项。来自@benaadams 的 dotnet/aspnetcore#31311将 WebSocket 请求中众所周知的标头值替换为内部字符串,这允许在头解析过程中分配的字符串被垃圾回收,减少了长期存在的WebSocket连接的内存使用。dotnet/aspnetcore#30771重构了 Kestrel 中的 Sockets 层,首先避免分配SocketReceiver对象+ SocketAwaitableEventArgs,并将其合并为单个对象,这节省了几个字节,并导致每个连接分配的对象较少。该 PR 还汇集了 SocketSender 类,因此您现在平均拥有多个核心 SocketSender,而不是为每个连接创建一个。因此,在下面的基准测试中,当我们有10,000个连接时,在我的机器上只分配了16个连接,而不是10,000个,这节省了~ 46mb !

另一个类似的大小变化是dotnet/runtime#49123,它增加了对SslStream中零字节读取的支持,这样我们的10,000个空闲连接从SslStream分配的~ 46mb到~2.3 MB。dotnet/runtime#49117在 StreamPipeReader 上添加了对零字节读取的支持,然后 Kestrel 在 dotnet/aspnetcore#30863中使用它开始在 SslStream 中使用零字节读取。

所有这些变化的最终结果是大量减少空闲连接的内存使用。

下面的数字不是来自于BenchmarkDotNet应用程序,因为它测量空闲连接,而且更容易用客户机和服务器应用程序进行设置。

控制台和 WebApplication 代码粘贴在以下要点中:

https://gist.github.com/BrennanConroy/02e8459d63305b4acaa0a021686f54c7

下面是10000个空闲的安全WebSocket连接(WSS)在不同框架上占用服务器的内存。

201a9e60e7afa6b0dac2626c33fc4afc.png

这比 net5 减少了近 4 倍的内存。

dotnet/runtime#49270

https://github.com/dotnet/runtime/pull/49270

dotnet/aspnetcore#31308

https://github.com/dotnet/aspnetcore/pull/31308

dotnet/aspnetcore#30769

https://github.com/dotnet/aspnetcore/pull/30769

benaadams

https://github.com/benaadams

dotnet/aspnetcore#31311 

https://github.com/dotnet/aspnetcore/pull/31311

内部字符串

https://en.wikipedia.org/wiki/String_interning

dotnet/aspnetcore#30771

https://github.com/dotnet/aspnetcore/pull/30771

dotnet/runtime#49123

https://github.com/dotnet/runtime/pull/49123

dotnet/runtime#49117

https://github.com/dotnet/runtime/pull/49117

dotnet/aspnetcore#30863

https://github.com/dotnet/aspnetcore/pull/30863

实体框架核心

EF Core在6.0版本中做了大量的改进,查询执行速度提高了31%,TechEmpower fortune的基准运行时间更新、优化基准和EF的改进提高了70%。

这些改进来自于对象池的改进,智能检查是否启用了遥测技术,以及添加一个选项,当你知道你的应用程序安全地使用DbContext时,可以选择退出线程安全检查。

请参阅发布实体框架核心6.0预览版4:性能版的博客文章,其中详细强调了许多改进。

TechEmpower fortune

https://www.techempower.com/benchmarks/#section=data-r20

请参阅发布实体框架核心6.0预览版4:性能版的博客文章

https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-4-performance-edition/

Blazor

本机byte[]互操作

Blazor现在在执行JavaScript互操作时对字节数组有了有效的支持。以前,发送到和从JavaScript的字节数组是Base64编码的,因此它们可以被序列化为JSON,这增加了传输大小和CPU负载。Base64编码现在已经在.NET6中进行了优化,允许用户透明地使用.NET中的byte[]和JavaScript中的Uint8Array。说明如何将此特性用于JavaScript到.NET和.NET到JavaScript。

让我们看一个快速的基准测试,看看byte[]互操作在.NET 5和.NET 6中的区别。以下Razor代码创建了一个22 kB的字节[],并将其发送给JavaScript的receiveAndReturnBytes函数,该函数立即返回字节[]。这种数据往返重复了10,000次,时间数据被打印到屏幕上。这段代码对于.NET 5和.NET 6是相同的。

<button @onclick="@RoundtripData">Roundtrip Data</button>
<hr />
@Message
@code {public string Message { get; set; } = "Press button to benchmark";private async Task RoundtripData(){var bytes = new byte[1024*22];List<double> timeForInterop = new List<double>();var testTime = DateTime.Now;for (var i = 0; i < 10_000; i++){var interopTime = DateTime.Now;var result = await JSRuntime.InvokeAsync<byte[]>("receiveAndReturnBytes", bytes);timeForInterop.Add(DateTime.Now.Subtract(interopTime).TotalMilliseconds);}Message = $"Round-tripped: {bytes.Length / 1024d} kB 10,000 times and it took on average {timeForInterop.Average():F3}ms, and in total {DateTime.Now.Subtract(testTime).TotalMilliseconds:F1}ms";}
}

接下来我们来看一下receiveAndReturnBytes JavaScript函数。在.NET 5。我们必须首先将Base64编码的字节数组解码为Uint8Array,以便它可以在应用程序代码中使用。然后,在将数据返回给服务器之前,我们必须将其重新编码为Base64。

function receiveAndReturnBytes(bytesReceivedBase64Encoded) {const bytesReceived = base64ToArrayBuffer(bytesReceivedBase64Encoded);// Use Uint8Array data in applicationconst bytesToSendBase64Encoded = base64EncodeByteArray(bytesReceived);if (bytesReceivedBase64Encoded != bytesToSendBase64Encoded) {throw new Error("Expected input/output to match.")}return bytesToSendBase64Encoded;
}
// https://stackoverflow.com/a/21797381
function base64ToArrayBuffer(base64) {const binaryString = atob(base64);const length = binaryString.length;const result = new Uint8Array(length);for (let i = 0; i < length; i++) {result[i] = binaryString.charCodeAt(i);}return result;
}
function base64EncodeByteArray(data) {const charBytes = new Array(data.length);for (var i = 0; i < data.length; i++) {charBytes[i] = String.fromCharCode(data[i]);}const dataBase64Encoded = btoa(charBytes.join(''));return dataBase64Encoded;
}

编码/解码在客户机和服务器上都增加了巨大的开销,同时还需要大量的样板代码。那么在.NET 6中如何实现呢? 嗯,它相当简单:

function receiveAndReturnBytes(bytesReceived) {// bytesReceived comes as a Uint8Array ready for use// and can be used by the application or immediately returned.return bytesReceived;
}

因此,编写它肯定更容易,但它的性能如何呢?分别在.NET 5和.NET 6的blazorserver模板中运行这些代码片段,在Release配置下,我们看到.NET 6在byte[]互操作方面有78%的性能提升!

请注意,流式互操作支持还可以有效下载(大)文件,有关更多详细信息,请参阅文档。

InputFile 组件已升级为通过 dotnet/aspnetcore#33900 使用流式传输。

7ad0ac3047fd7125e4db6d416ed78c33.png

此外,这个字节数组互操作支持在框架中被用来支持JavaScript和.NET之间的双向流互操作。用户现在能够传输任意二进制数据。有关从 .NET 流式传输到 JavaScript 的文档可在此处获得,JavaScript 到 .NET 文档可在此处获得。

JavaScript到.NET

https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/using-directive#global-modifier

.NET到JavaScript

https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0#byte-array-support

.NET 流式传输到 JavaScript

https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-6.0#stream-from-net-to-javascript

JavaScript 到 .NET 文档

https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0#stream-from-javascript-to-net

输入文件

使用上面提到的Blazor Streaming Interop,我们现在支持通过InputFile组件上传大文件(以前的上传限制在2GB左右)。由于使用了本地byte[]流,而不是使用Base64编码,该组件的速度也有了显著提高。例如,例如,与.NET 5相比,一个100mb文件的上传速度要快77%。

e4073ba5a21a4888fb11cc9edbafebca.png

请注意,流式互操作支持还可以有效下载(大)文件,有关更多详细信息,请参阅文档。

InputFile 组件已升级为通过dotnet/aspnetcore#33900使用流式传输。

上传大文件

https://docs.microsoft.com/en-us/aspnet/core/blazor/file-uploads?view=aspnetcore-6.0&pivots=server

文档

https://docs.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-6.0

dotnet/aspnetcore#33900

https://github.com/dotnet/aspnetcore/pull/33900

大杂烩

来自@benaadams 的 dotnet/aspnetcore#30320 对我们的 Typescript 库进行了现代化改造并对其进行了优化,因此网站加载速度更快。signalr.min.js 文件从 36.8 kB 压缩和 132 kB 未压缩变为 16.1 kB 压缩和 42.2 kB 未压缩。blazor.server.js 文件压缩后为 86.7 kB,未压缩时为 276 kB,压缩后为 43.9 kB,未压缩时为 130 kB。

@benaadams 的 dotnet/aspnetcore#31322在从连接功能集合中获取常用功能时删除了一些不必要的强制转换。这在访问集合中的常见特征时提供了约 50% 的改进。不幸的是,在基准测试中看到性能改进是不可能的,因为它需要一堆内部类型,所以我将在此处包含来自 PR 的数字,如果您有兴趣运行它们,PR 包括可以运行的基准反对内部代码。

d2b145d85db7784a718175373e583d13.png

dotnet/aspnetcore#31519 也来自@benaadams,将默认接口方法添加到 IHeaderDictionary 类型,以通过以标头名称命名的属性访问公共标头。访问标题字典时不再输入错误的常见标题!这篇博客文章中更有趣的是,这个改变允许服务器实现返回一个自定义标头字典,以更优化地实现这些新的接口方法。例如,服务器可能会将标头值直接存储在一个字段中,并直接返回该字段,而不是在内部字典中查询标头值,这需要对键进行哈希并查找条目。在某些情况下,当获取或设置标头值时,此更改可带来高达480%的改进。再一次,为了正确地对这个变化进行基准测试,以显示它需要使用内部类型进行设置,所以我将包括来自PR的数字,对于那些有兴趣尝试它的人来说,PR包含在内部代码上运行的基准测试。

842fd06d350990739fbdaa711135ba48.png

dotnet/aspnetcore#31466使用 .NET 6 中引入的新 CancellationTokenSource.TryReset() 方法在连接关闭但未取消的情况下重用 CancellationTokenSource。下面的数字是通过运行bombardier对Kestrel的125个连接收集的,它运行了大约10万个请求。

0794d69a910da74001b8f52860187334.png

dotnet/aspnetcore#31528和dotnet/aspnetcore#34075分别对重用HTTPS握手和HTTP3流的CancellationTokenSource做了类似的更改。

dotnet/aspnetcore#31660通过在SignalR中为整个流重用分配的StreamItem对象,而不是为每个流项分配一个,提高了服务器对客户端流的性能。而dotnet/aspnetcore#31661将HubCallerClients对象存储在SignalR连接上,而不是为每个Hub方法调用分配它。

@ShreyasJejurkar的 dotnet/aspnetcore#31506重构了WebSocket握手的内部结构,以避免临时List分配。@gfoidl 中的 dotnet/aspnetcore#32829重构QueryCollection以减少分配和向量化一些代码。@benaadams 的 dotnet/aspnetcore#32234 删除了 HttpRequestHeaders 枚举中未使用的字段,该字段通过不再为每个枚举的标头分配字段来提高性能。

来自 martincostello 的 dotnet/aspnetcore#31333 将 Http.Sys 转换为使用 LoggerMessage.Define,这是高性能日志记录 API。这避免了不必要的值类型装箱、日志格式字符串的解析,并且在某些情况下避免了在日志级别未启用时分配字符串或对象。

dotnet/aspnetcore#31784添加了一个新的 IApplicationBuilder。使用重载来注册中间件,以避免在运行中间件时进行一些不必要的按请求分配。旧代码如下所示:

app.Use(async (context, next) =>
{await next();
});
新代码如下:
app.Use(async (context, next) =>
{await next(context);
});

下面的基准测试模拟中间件管道,而不需要设置服务器来展示改进。使用int代替HttpContext用于请求,中间件返回一个完成的任务。

dotnet run -c Release -f net6.0 --runtimes net6.0 --filter *UseMiddlewareBenchmark*
static private Func<Func<int, Task>, Func<int, Task>> UseOld(Func<int, Func<Task>, Task> middleware)
{return next =>{return context =>{Func<Task> simpleNext = () => next(context);return middleware(context, simpleNext);};};
}
static private Func<Func<int, Task>, Func<int, Task>> UseNew(Func<int, Func<int, Task>, Task> middleware)
{return next => context => middleware(context, next);
}
Func<int, Task> Middleware = UseOld((c, n) => n())(i => Task.CompletedTask);
Func<int, Task> NewMiddleware = UseNew((c, n) => n(c))(i => Task.CompletedTask);
[Benchmark(Baseline = true)]
public Task Use()
{return Middleware(10);
}
[Benchmark]
public Task UseNew()
{return NewMiddleware(10);
}

d7627d4fe298a2a8e1b0290cfbb909ed.png

dotnet/aspnetcore#30320

https://github.com/dotnet/aspnetcore/pull/30320

dotnet/aspnetcore#31322

https://github.com/dotnet/aspnetcore/pull/31322

dotnet/aspnetcore#31519

https://github.com/dotnet/aspnetcore/pull/31519

默认接口方法

https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/

dotnet/aspnetcore#31466

https://github.com/dotnet/aspnetcore/pull/31466

bombardier

https://github.com/codesenberg/bombardier

dotnet/aspnetcore#31528

https://github.com/dotnet/aspnetcore/pull/31528

dotnet/aspnetcore#34075

https://github.com/dotnet/aspnetcore/pull/34075

dotnet/aspnetcore#31660

https://github.com/dotnet/aspnetcore/pull/31660

服务器对客户端流

https://docs.microsoft.com/en-us/aspnet/core/signalr/streaming?view=aspnetcore-5.0#server-to-client-streaming

dotnet/aspnetcore#31661

https://github.com/dotnet/aspnetcore/pull/31661

ShreyasJejurkar

https://github.com/ShreyasJejurkar

dotnet/aspnetcore#32234

https://github.com/dotnet/aspnetcore/pull/32234

martincostello

https://github.com/martincostello

dotnet/aspnetcore#31333

https://github.com/dotnet/aspnetcore/pull/31333

LoggerMessage.Define

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/loggermessage?view=aspnetcore-5.0

dotnet/aspnetcore#31784

https://github.com/dotnet/aspnetcore/pull/31784

总结

希望您喜欢阅读 ASP.NET Core 6.0 中的一些改进!我鼓励你去看看.NET 6博客中关于运行时性能改进的文章。

https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290777.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为服务器只显示一个下划线,华为官方解释:为什么鸿蒙系统logo下面会有一条下划线...

HarmonyOS 的 Logo 中为什么有一横&#xff1f;为什么这一横偏偏是蓝色&#xff1f;HarmonyOS 的字体设计又藏着什么奥秘&#xff1f;6月10日晚&#xff0c;华为官方微博对鸿蒙系统LOGO设计寓意&#xff0c;作出了官方科普。下面就来为你一一解答在现代汉语中“旦”字与鸿蒙OS中…

ORACLE利用STANDBY端RMAN备份进行数据恢复

这里记录一下流程&#xff0c;有我和同事问心进行测试 dataguard主库和物理备库主要是controlfile文件有区别&#xff0c;用restore可以查看含有primary,standby关键字 RMAN> restore ; RMAN-00571: RMAN-00569: ERROR MESSAGE STACK FOLLOWS RMAN-00571: RMAN-00558: e…

腾讯急招多名.NET Core,5年30k!

金三银四跳槽季&#xff0c;腾讯急招5年左右.NET Core高级开发岗&#xff0c;基本月薪能到30k&#xff0c;心动吗&#xff1f;这里推荐个.NET跳槽大厂交流群&#xff0c;有技术交流&#xff0c;有面经分享&#xff0c;还有内推通道&#xff0c;据说有一定几率降低学历要求&…

perl学习笔记——目录操作

在目录书中移动 chdir 操作副改变当前的工作目录。它和shell中cd命令类似&#xff1a; chdir ‘/etc’ or die “cannot chdir to /etc:$1”; 注意&#xff1a;工作目录不能更改的&#xff0c;也就是说Perl程序返回后一定会回到所在的工作目录。 如果调用chdir时不加参数&#…

凌动服务器系列,凌动也能造服务器?超微又出怪异新品

【IT168 专稿】上月初举行的英特尔春季IDF上&#xff0c;记者看到超微展示了采用独特设计的2U Twin系列高密度Nehalem服务器&#xff0c;该服务器采用了全冗余设计&#xff0c;包括主板在内的所有部件都有两个互为备份。可以说超微一直以来都以自身独特的设计理念和大胆的实践拓…

C语言——关于数据在内存中存储的练习

大家好&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各位→…

Avalonia跨平台入门第九篇之控件置顶和置底

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果;今天趁着有时间接着对拖放到Canvas上的控件进行置顶和置底切换的效果,最终实现的效果如下图:关于置顶和置底的实现代码:接下来的文章中我会再来分享在Canvas上控件的锁定效果;…

C/C++之常用字符串比较总结

1、std::string比较 我们一般用str1.compare(str2) 0来实现 2、const char* 的比较 我们一般用strcmp(p1, p2) 0来实现 3、代码 4、结果 str1 str4 str5 is null p1 p3

【C#/.NET】控制台上动态构建中间件管道

如上图所示&#xff1a;我们将会在下面文章上一步一步变形实现出这样的功能。一、傻瓜式执行演示首先建立控制台项目&#xff0c;创建Begin() FirstMiddleware() SecondMiddleware() End() 三个函数1 /// <summary>2 /// 开始执行前3 /// </summ…

SON Web Token设计单点登录系统

2019独角兽企业重金招聘Python工程师标准>>> 上次在《JSON Web Token - 在Web应用间安全地传递信息》中我提到了JSON Web Token可以用来设计单点登录系统。我尝试用八幅漫画先让大家理解如何设计正常的用户认证系统&#xff0c;然后再延伸到单点登录系统。 如果还没…

Avalonia跨平台入门第十篇之控件的锁定

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底;今天趁着有时间接着对拖放到Canvas上的控件进行锁定的效果,最终实现的效果如下图:关于控件的锁定实现代码:接下来的文章中我会分享控件在Canvas范围内拖拽和…

ios之第一个图形化界面

1、创建ios项目 1、create Xcode ->simpleViewApplication -> input Program name 2、在控制器里面加入代码 我们在viewControl.m里面加上UILabel控件&#xff0c;这个控件和Android 里面的TextView类似&#xff0c;具体代码如下// // ViewController.m // SecondHello…

Memcached简介

在Web服务开发中&#xff0c;服务端缓存是服务实现中所常常采用的一种提高服务性能的方法。其通过记录某部分计算结果来尝试避免再次执行得到该结果所需要的复杂计算&#xff0c;从而提高了服务的运行效率。 除了能够提高服务的运行效率之外&#xff0c;服务端缓存还常常用来提…

JAVA设计模式之门面模式(外观模式)

医院的例子 现代的软件系统都是比较复杂的&#xff0c;设计师处理复杂系统的一个常见方法便是将其“分而治之”&#xff0c;把一个系统划分为几个较小的子系统。如果把医院作为一个子系统&#xff0c;按照部门职能&#xff0c;这个系统可以划分为挂号、门诊、划价、化验、收费、…

里程碑 .Net7再更新,从此彻底碾压Java!

.NET 7 Preview1发布了&#xff0c;没时间实操&#xff1f;先快来看看.NET7的七项重大改进&#xff01;1、不再支持.NET 7应用程序、运行时和SDK的多级查找&#xff08;MLL&#xff09;2、PATH停止向.NET 7运行时和SDK添加32位.NET3、默认情况下&#xff0c; dotnet build/publ…

软件架构知识体系

2019独角兽企业重金招聘Python工程师标准>>> 由于[GOF95]是论述软件模式的著作的第一本&#xff0c;也是OO设计理论著作中最流行的一本&#xff0c;因此有些人常常使用设计模式&#xff08;Design Pattern&#xff09;一词来指所有直接处理软件的架构、设计、程序实…

C#不要再使用Npoi啦,使用MiniExcel操作Excel文件更快更高效!

1.简介MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。目前主流框架如Npoi 需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题。MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本1000多MB占用降低到几MB&#xff0c;避免内…

go和python切片的不同

2019独角兽企业重金招聘Python工程师标准>>> go有切片slice类型&#xff0c;python有列表和元组&#xff0c;这两种语言都有切片操作。 但是它们的切片操作是完全不同的。 首先说第一个&#xff0c;go的切片&#xff0c;其成员是相同类型的&#xff0c;python的列…

编程算法 - 切割排序 代码(C)

切割排序 代码(C)本文地址: http://blog.csdn.net/caroline_wendy排序切割, 把一个数组分为, 大于k\小于k\等于k的三个部分.能够使用高速排序的Partition函数, 进行处理, 把大于k的放在左边, 小于k的放在右边.使用一个变量记录中间的位置, 则时间复杂度为O(3n/2).代码:/** main…

【C#/.NET】.NET6中全局异常处理

微信公众号&#xff1a;趣编程ACE关注可了解每日一更的.NET日常实战开发技巧&#xff0c;欢迎公众号留言开发 获取源码;.NET6中全局异常处理异常处理是我们在程序开发中不可或缺的一环&#xff0c;下文我将会结合程序Sample讲解如何在.NET6中有效处理异常。Try-Ctach 块包裹自定…