.NET9 實現斐波那契數列(FibonacciSequence)性能測試

.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;最后經過一番搜索 在官方…