.NET 平台上实现 斐波那契数列 并使用 BenchmarkDotNet 进行性能测试,是评估不同算法实现方式性能表现的一种高效且标准化的方法。通过该方式,可以对比递归、迭代、记忆化递归以及结合高性能优化技术(如 Span<T>Memory<T>ArrayPool<T>)的多种实现,在不同输入规模下的执行时间、内存分配和垃圾回收行为。

整个过程包括:

  1. 选择合适的斐波那契实现方式

    • 递归实现:直观但效率低下,尤其在大数值时存在指数级时间复杂度。
    • 迭代实现:性能最优,适用于大多数生产环境。
    • 记忆化递归:通过缓存减少重复计算,提升递归效率。
    • 结合 ArrayPool 的记忆化递归:避免频繁内存分配,降低 GC 压力。
    • 使用 Span<T>Memory<T> 的实现:进一步优化内存访问效率,支持更灵活的异步或池化操作。
  2. 构建基准测试类
    使用 BenchmarkDotNet 提供的 [Benchmark] 特性对每个实现方法进行标注,并通过 [Params] 指定多个输入值(如 N = 10, 30, 40),以模拟不同场景下的运行情况。

  3. 启用诊断功能
    在基准测试类上添加 [MemoryDiagnoser] 等特性,启用内存统计功能,获取每次调用的堆内存分配信息,帮助识别潜在的性能瓶颈。

  4. 运行基准测试
    使用 BenchmarkRunner.Run<T>() 启动测试,生成结构化的性能报告,包含 平均耗时(Mean)、误差范围(Error)、标准差(StdDev)、Gen0/Gen1 垃圾回收次数及内存分配量 等关键指标。

  5. 分析结果并优化实现
    根据测试报告数据,判断哪种实现方式在特定场景下具有最佳性能表现。例如,迭代法通常最快且无内存分配,而结合 ArrayPool<T> 的记忆化递归则在保留递归风格的同时大幅提升了性能。

最终,这一流程不仅验证了各类斐波那契实现的实际性能差异,也为实际项目中选择合适的算法提供了可靠的数据支撑。

项目准备

  • 项目环境
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net9.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><PublishAot>true</PublishAot><InvariantGlobalization>true</InvariantGlobalization></PropertyGroup><ItemGroup><PackageReference Include="Datadog.Trace.BenchmarkDotNet" Version="2.61.0" /></ItemGroup></Project>
  • 斐波那契数列实现
// =============================
// FibonacciSequence 斐波那契数列实现
// =============================using System.Buffers;namespace FibonacciSequenceTest;internal class FibonacciSequence
{// 递归实现(效率低)public static long Recursive(int n){if (n <= 1) return n;return Recursive(n - 1) + Recursive(n - 2);}// 迭代实现(高效)public static long Iterative(int n){if (n <= 1) return n;long a = 0, b = 1;for (int i = 2; i <= n; i++){long temp = a + b;a = b;b = temp;}return b;}// 带缓存的递归实现(记忆化)public static long Memoized(int n){var memo = new long[n + 1];return FibMemo(n, memo);}private static long FibMemo(int n, long[] memo){if (n <= 1) return n;if (memo[n] != 0) return memo[n];memo[n] = FibMemo(n - 1, memo) + FibMemo(n - 2, memo);return memo[n];}// 使用 ArrayPool 优化的记忆化递归实现public static long MemoizedWithPooling(int n){// 从 ArrayPool 获取足够大小的缓存数组int length = n + 1;var memo = ArrayPool<long>.Shared.Rent(length);try{return FibMemo(n, memo);}finally{// 用完后归还数组,避免内存泄漏if (memo != null)ArrayPool<long>.Shared.Return(memo);}}// 使用 ArrayPool + Span 优化的记忆化递归实现public static long MemoizedWithSpan(int n){int length = n + 1;var memo = ArrayPool<long>.Shared.Rent(length);try{return FibMemoWithSpan(n, memo.AsSpan());}finally{if (memo != null)ArrayPool<long>.Shared.Return(memo);}}private static long FibMemoWithSpan(int n, Span<long> memo){if (n <= 1) return n;if (memo[n] != 0) return memo[n];memo[n] = FibMemoWithSpan(n - 1, memo) + FibMemoWithSpan(n - 2, memo);return memo[n];}// 使用 ArrayPool + Memory 优化的记忆化递归实现public static long MemoizedWithMemory(int n){int length = n + 1;var memo = ArrayPool<long>.Shared.Rent(length);try{return FibMemoWithMemory(n, memo.AsMemory());}finally{if (memo != null)ArrayPool<long>.Shared.Return(memo);}}private static long FibMemoWithMemory(int n, Memory<long> memo){if (n <= 1) return n;// 将 Memory<long> 转换为 Span<long>,以支持索引操作Span<long> span = memo.Span;if (span[n] != 0) return span[n];span[n] = FibMemoWithMemory(n - 1, memo) + FibMemoWithMemory(n - 2, memo);return span[n];}
}
  • FibonacciSequence 测试类
// =============================
// FibonacciSequence 测试类
// =============================using BenchmarkDotNet.Attributes;
using Datadog.Trace.BenchmarkDotNet;namespace FibonacciSequenceTest;[DatadogDiagnoser]
[MemoryDiagnoser]
public class FibonacciBenchmark
{[Params(10, 30, 40)] // 测试不同的 n 值public int N { get; set; }[Benchmark]public long RecursiveFibonacci() => FibonacciSequence.Recursive(N);[Benchmark]public long IterativeFibonacci() => FibonacciSequence.Iterative(N);[Benchmark]public long MemoizedFibonacci() => FibonacciSequence.Memoized(N);[Benchmark]public long MemoizedWithPoolingFibonacci() => FibonacciSequence.MemoizedWithPooling(N);[Benchmark]public long MemoizedWithSpanFibonacci() => FibonacciSequence.MemoizedWithSpan(N);[Benchmark]public long MemoizedWithMemoryFibonacci() => FibonacciSequence.MemoizedWithMemory(N);
}
  • 使用基准测试

Program.cs 文件中添加如下代码:

using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Datadog.Trace.BenchmarkDotNet;namespace FibonacciSequenceTest;internal class Program
{static void Main(string[] args){Console.WriteLine("Hello, SortingBenchmark!");var fibonacciSummary = BenchmarkRunner.Run<FibonacciBenchmark>();}
}

启动测试

进入项目,使用 pwsh 执行如下命令:

dotnet run -c Release

这段文本是一个使用 BenchmarkDotNet 工具对不同 斐波那契数列(Fibonacci)算法实现 的性能基准测试结果报告。它对比了多种实现方式在不同输入规模 N 下的执行效率、内存分配等指标。

FibonacciBenchmark


以下是关键内容的通俗解释:

📊 表格结构说明

列名含义
Method测试的方法名称(不同的 Fibonacci 实现)
N输入参数,表示求第 N 个斐波那契数
Mean平均耗时(单位:纳秒 ns 或 微秒 μs)
Error置信区间的一半(99.9% 置信度)
StdDev标准差,衡量运行时间波动
Median中位数,排除极端值后的时间
Gen0Gen0 垃圾回收次数(每千次操作)
Allocated每次操作分配的托管内存大小

🧪 被测试的斐波那契实现方法

方法名实现方式是否推荐
RecursiveFibonacci普通递归(无优化)❌ 不推荐
IterativeFibonacci迭代法(最高效)✅ 强烈推荐
MemoizedFibonacci使用数组缓存的记忆化递归⚠️ 可用但有内存分配
MemoizedWithPoolingFibonacci使用 ArrayPool<long> 缓存数组优化✅ 推荐
MemoizedWithSpanFibonacci使用 ArrayPool<long> + Span<long> + 缓存✅ 推荐
MemoizedWithMemoryFibonacci使用 ArrayPool<long> + Memory<long> + 缓存✅ 推荐

📈 性能对比分析(按 N 分组)

N = 10 时:

方法平均耗时内存分配
RecursiveFibonacci251.435 ns-
IterativeFibonacci7.234 ns-
MemoizedFibonacci63.627 ns112 B
MemoizedWithPoolingFibonacci18.526 ns-
MemoizedWithSpanFibonacci21.416 ns-
MemoizedWithMemoryFibonacci20.367 ns-

📌 结论:

  • 迭代法最快(仅 7ns)
  • 普通递归较慢
  • 使用池化或 Span/ Memory 优化后的记忆化递归显著优于普通递归

N = 30 时:

方法平均耗时内存分配
RecursiveFibonacci3,372,317 ns(3.37ms)-
IterativeFibonacci26.832 ns-
MemoizedFibonacci301.255 ns272 B
MemoizedWithPoolingFibonacci18.624 ns-
MemoizedWithSpanFibonacci19.883 ns-
MemoizedWithMemoryFibonacci24.130 ns-

📌 结论:

  • 普通递归性能急剧下降(指数级增长)
  • 其他优化方法依然保持稳定低耗时
  • 迭代法仍是最快

N = 40 时:

方法平均耗时内存分配
RecursiveFibonacci416,127,408 ns(约 416ms)-
IterativeFibonacci35.565 ns-
MemoizedFibonacci436.763 ns352 B
MemoizedWithPoolingFibonacci18.548 ns-
MemoizedWithSpanFibonacci19.698 ns-
MemoizedWithMemoryFibonacci20.206 ns-

📌 结论:

  • 普通递归已变得不可接受
  • 所有优化版本仍保持微秒级响应
  • 迭代法依旧最优

✅ 总结与建议

特性推荐实现
最快实现IterativeFibonacci(迭代法)
最节省内存MemoizedWithPoolingFibonacci(结合 ArrayPool)
支持异步和长期持有MemoizedWithMemoryFibonacci
保留递归风格又兼顾性能MemoizedWithPoolingFibonacciMemoizedWithSpanFibonacci

📝 小结

方法性能内存是否推荐
普通递归❌ 极慢
迭代法✅ 极快无分配✅ 强烈推荐
记忆化递归⚠️ 中等一般
记忆化 + ArrayPool/Span/Memory✅ 快无分配✅ 推荐保留递归风格时使用

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

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

相关文章

三、docker软件安装:gitlab,nexus,mysql8,redis,nacos,nginx

目录 1.gitlab安装 2.nexus安装 (1)下载启动 (2)设置中央仓库远程地址 (3)配置maven的settings.xml 3.mysql8安装 4.redis安装 5.nacos安装 6.nginx安装 1.gitlab安装 #创建目录 cd /usr/local/ mkdir docker cd docker/ mkdir gitlab_docker cd gitlab_docker…

【与AI+】SAP WEBGUI集成开发与SAP INTERNET服务的关系

前言&#xff1a;这是我的水水专栏第五篇文章&#xff0c;这个专栏呢&#xff0c;是放一些我向AI提问的问题&#xff0c;以及AI的回答。因为感觉真的好方便哈哈哈~ 我不是很确定我的专栏文章内容是否涉及版权&#xff0c;以及也不确定这些整合过的文字是否涉嫌抄袭&#xff0c…

浅谈几种js设计模式

JavaScript设计模式是开发中常用的一种解决方案&#xff0c;它们帮助开发者以一种更结构化、更易维护的方式编写代码。本文将深入介绍几种常见的JavaScript设计模式&#xff0c;包括单例模式、工厂模式、观察者模式和策略模式。 一、单例模式&#xff08;Singleton Pattern&am…

手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程

目录 一、虚拟 DOM 的核心概念 二、虚拟 DOM 到真实 DOM 的流程 三、手写虚拟 DOM 到真实 DOM 的实现 1. 定义虚拟 DOM 的结构&#xff08;VNode&#xff09; 2. 创建虚拟 DOM 转真实 DOM 的函数 3. 挂载虚拟 DOM 到页面 4. 更新虚拟 DOM 的过程&#xff08;Diff 算法简化…

jmm--volatile

指令重排基础概念 在现代处理器和编译器为了提高程序执行效率&#xff0c;会对指令进行优化&#xff0c;其中一种优化方式就是指令重排序。在单线程环境下&#xff0c;指令重排序不会影响最终执行结果&#xff0c;因为处理器和编译器会保证重排序后的执行结果与按照代码顺序执行…

【硬件开发】滤波电容的选择:原理、计算与多电压值应用实践

滤波电容的选择&#xff1a;原理、计算与多电压值应用实践 1. 引言 在现代电子系统中&#xff0c;稳定的电源供应是保证电路可靠运行的基础。然而&#xff0c;电源线上往往不可避免地存在各种噪声和纹波&#xff0c;这些干扰可能源自电源本身&#xff08;如整流后的脉动直流&…

【seismic unix数据生成-unif2】

Seismic Unix简介 Seismic Unix&#xff08;SU&#xff09;是由科罗拉多矿业学院&#xff08;Colorado School of Mines&#xff09;开发的开源地震数据处理软件包&#xff0c;专为地震勘探数据分析和研究设计。它提供了一系列命令行工具&#xff0c;支持从数据加载、处理到可…

【逆向思考 并集查找】P2391 白雪皑皑|省选-

本文涉及知识点 C并集查找 P2391 白雪皑皑 题目背景 “柴门闻犬吠&#xff0c;风雪夜归人”&#xff0c;冬天&#xff0c;不期而至。千里冰封&#xff0c;万里雪飘。空中刮起了鸭毛大雪。雪花纷纷&#xff0c;降落人间。 美能量星球&#xff08;pty 在 spore 上的一个殖民地…

一文讲清楚React中setState的使用方法和机制

文章目录 一文讲清楚React中setState的使用方法和机制1. setState是什么2. setState方法详解2.1 setState参数详解2.2 setState同步异步问题2.2.1 setState异步更新2.2.2 setState同步更新 一文讲清楚React中setState的使用方法和机制 1. setState是什么 React中&#xff0c;…

01_软件卓越之道:功能性与需求满足

引言 在软件的世界里&#xff0c;功能性是产品与用户之间的第一桥梁。一个软件即使拥有华丽的界面和极致的性能&#xff0c;如果不能解决用户的核心需求&#xff0c;也终将被市场淘汰。本文将深入探讨如何确保软件的功能性与用户需求完美契合。 1. 需求理解&#xff1a;从模糊…

StarRocks × Tableau 连接器完整使用指南 | 高效数据分析从连接开始

一、导语&#xff1a;为什么选择 StarRocks Tableau 连接器&#xff1f; 在当今数据驱动的商业环境中&#xff0c;企业不仅需要一个能够处理海量数据的高性能分析数据库&#xff0c;还需要一个直观、强大的可视化工具来解读数据背后的故事。StarRocks 作为新一代极速全场景 MP…

基于 SpringBoot+VueJS 助农生鲜销售系统设计与实现7000字论文实现

摘要本论文设计并实现了一个基于 SpringBoot 和 VueJS 的助农生鲜销售系统。系统采用前后端分离架构&#xff0c;前端使用 VueJS 框架实现用户界面&#xff0c;后端使用 SpringBoot 框架构建服务&#xff0c;通过 MyBatis 实现数据持久化。系统实现了农产品展示、在线购物、订单…

Pytest 测试发现机制详解:自动识别测试函数与模块

概述 在编写自动化测试时,如何让 Pytest 自动找到你的测试代码 是一个非常基础但重要的问题。Pytest 通过其强大的 测试发现(Test Discovery)机制,能够自动扫描项目目录、识别测试模块和测试函数,从而大大简化了测试流程。 本文将为你详细讲解 Pytest 的测试发现机制,包…

MySQL 时间日期函数

时间日期类型 MySQL中主要支持以下几种时间日期类型&#xff1a; DATE - 日期类型 格式&#xff1a;YYYY-MM-DD范围&#xff1a;1000-01-01 到 9999-12-31示例&#xff1a;2023-05-20 TIME - 时间类型 格式&#xff1a;HH:MM:SS范围&#xff1a;-838:59:59 到 838:59:59示例&…

408第三季part2 - 计算机网络 - 物理层

理解 这里有8个波形&#xff0c;每个波形代表一个马原&#xff0c;一个马原代表多个比特&#xff0c;这里3个比特 求波特率就直接2W 求比特率就要乘log2V 这块记两公式就行&#xff0c;一个下面一个上面 题目 4个相位加4种幅度就是有16种波形 这里无噪声就是奈奎斯特定理 这…

iOS 集成RN Installing glog (0.3.5)报错的解决方案

在集成执行RN bundle exec pod install 命令到Installing glog (0.3.5)时报错,报错信息如下: Installing glog (0.3.5) [!] /bin/bash -c set -e #!/bin/bash # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license …

【进阶篇-消息队列】——MQTT协议如何支持海量的在线IoT设备

目录 一、什么是IoT二、MQTT 和其他消息队列的传输协议有什么不同三、如何选择 MQTT 产品四、MQTT 集群如何支持海量在线的 IoT 设备五、总结本文来源:极客时间vip课程笔记 一、什么是IoT IoT,也就是物联网,物联网这个词儿,它的含义还不那么直观,但你看它的英文:IoT,也就…

Chat Model API

聊天模型API为开发人员提供了将人工智能聊天完成功能集成到应用程序中的能力。它利用预训练的语言模型&#xff0c;如GPT&#xff08;生成预训练转换器&#xff09;&#xff0c;以自然语言对用户输入生成类似人类的响应。 API通常通过向人工智能模型发送提示或部分对话来工作&…

【黑群晖】自组硬件/旧电脑nas改造(三)——使用Jellyfin创建家庭影音库

一、打开套件中心安装Jellyfin套件 如果找不到Jellyfin套件&#xff0c;需要手动添加三方套件源&#xff1a; 《群晖NAS必学技能&#xff1a;一键解锁三方套件源&#xff0c;PT下载影音播放全搞定&#xff01;》 二、配置Jellyfin 访问http://群晖IP:8096 进入Jellyfin初始化界…

泰山派编译debian报错 lb config: unrecognized option ‘--debootstrap-options‘

简介 最近在编译泰山派 编译buildroot系统正常&#xff0c;但是编译debian时总是报错说lb 找不到一些参数&#xff0c;如下图所示&#xff0c;应该当前的版本较低 不支持这些参数&#xff0c;我试了很多方法 升级次版本 但是提示的是最新的&#xff0c;最后经过一番搜索 在官方…