.NET8 究極のパフォーマンス最適化 プリミティブ - DateTime

.NET8 究極のパフォーマンス最適化 プリミティブ - DateTime

序文

前回の記事では列挙型の最適化について説明しました。今回は時刻形式である DateTime の最適化について見ていきます。

概要

例として DateTime と DateTimeOffset を示します。 dotnet/runtime#84963 は、DateTime{Offset} フォーマットのさまざまな側面を改善します。

  • フォーマット ロジックには、フォールバックとして使用するための一般的なサポートがあり、任意のカスタム フォーマットをサポートしますが、最も一般的なフォーマット専用のルーチンもあり、それらを最適化および調整できます。非常に人気のある「r」(RFC1123 パターン)および「o」(ラウンドトリップ日付/時刻パターン)形式には、すでに専用ルーチンが存在します。この PR では、さまざまなドメインで頻繁に使用される、不変カルチャで使用されるデフォルトの形式(「G」)、"s" 形式(並べ替え可能な日付/時刻パターン)、および "u" 形式(ユニバーサルな並べ替え可能な日付/時刻パターン)用の専用ルーチンを追加します。
  • 「U」形式 (ユニバーサル完全日付/時刻パターン) の場合、実装では常に新しいインスタンスとインスタンスが割り当てられることになり、まれなフォールバックの場合にのみ必要な場合でも、割り当てが大量に発生します。これにより問題は修正され、本当に必要な場合にのみ割り当てられるようになります。日付時刻形式情報グレゴリオ暦
  • 専用のフォーマット ルーチンがない場合、フォーマットは、指定されたスパン バッファ (通常は から) で開始され、必要に応じてメモリとともに拡大する内部呼び出しに対して実行されます。フォーマットが完了すると、フォーマットをトリガーしたメソッドに応じて、ジェネレーターは宛先範囲または新しい文字列にコピーされます。ただし、ビルダーにターゲット範囲のシードのみを提供する場合は、ターゲット範囲のコピーを回避できます。次に、フォーマットが完了したときにビルダーにまだ初期スパンが含まれている場合 (そこから何も拡張されていない)、すべてのデータが収まることがわかり、すべてのデータがすでにそこにあるため、コピーをスキップできます。 ref structValueListBuilder<T>stackallocArrayPool

次の例は、いくつかの効果を示しています。

 // dotnet run -c Release -f net7.0 --filter "*" --runtimes net7.0 net8.0 using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using System.Globalization; BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args); [HideColumns("Error", "StdDev", "Median", "RatioSD")] [MemoryDiagnoser(displayGenColumns: false)] public class Tests { private readonly DateTime _dt = new DateTime(2023, 9, 1, 12, 34, 56); private readonly char[] _chars = new char[100]; [Params(null, "s", "u", "U", "G")] public string Format { get; set; } [Benchmark] public string DT_ToString() => _dt.ToString(Format); [Benchmark] public string DT_ToStringInvariant() => _dt.ToString(Format, CultureInfo.InvariantCulture); [Benchmark] public bool DT_TryFormat() => _dt.TryFormat(_chars, out _, Format); [Benchmark] public bool DT_TryFormatInvariant() => _dt.TryFormat(_chars, out _, Format, CultureInfo.InvariantCulture); }

パフォーマンステストは次のとおりです。

方法

ランタイム

形式

平均

比率

割り当て済み

割り当て比率

DT_文字列

.NET 7.0

?

166.64ナノ秒

1.00

64 B

1.00

DT_文字列

.NET 8.0

?

102.45ナノ秒

0.62

64 B

1.00








DT_ToString不変

.NET 7.0

?

161.94ナノ秒

1.00

64 B

1.00

DT_ToString不変

.NET 8.0

?

28.74ナノ秒

0.18

64 B

1.00








DT_TryFormat

.NET 7.0

?

151.52ナノ秒

1.00

該当なし

DT_TryFormat

.NET 8.0

?

78.57ナノ秒

0.52

該当なし








DT_TryFormatInvariant

.NET 7.0

?

140.35ナノ秒

1.00

該当なし

DT_TryFormatInvariant

.NET 8.0

?

18.26ナノ秒

0.13

該当なし








DT_文字列

.NET 7.0

162.86ナノ秒

1.00

64 B

1.00

DT_文字列

.NET 8.0

109.49ナノ秒

0.68

64 B

1.00








DT_ToString不変

.NET 7.0

162.20ナノ秒

1.00

64 B

1.00

DT_ToString不変

.NET 8.0

102.71ナノ秒

0.63

64 B

1.00








DT_TryFormat

.NET 7.0

148.32ナノ秒

1.00

該当なし

DT_TryFormat

.NET 8.0

83.60ナノ秒

0.57

該当なし








DT_TryFormatInvariant

.NET 7.0

145.05ナノ秒

1.00

該当なし

DT_TryFormatInvariant

.NET 8.0

79.77ナノ秒

0.55

該当なし








DT_文字列

.NET 7.0

s

186.44ナノ秒

1.00

64 B

1.00

DT_文字列

.NET 8.0

s

29.35ナノ秒

0.17

64 B

1.00








DT_ToString不変

.NET 7.0

s

182.15ナノ秒

1.00

64 B

1.00

DT_ToString不変

.NET 8.0

s

27.67ナノ秒

0.16

64 B

1.00








DT_TryFormat

.NET 7.0

s

165.08ナノ秒

1.00

該当なし

DT_TryFormat

.NET 8.0

s

15.53ナノ秒

0.09

該当なし








DT_TryFormatInvariant

.NET 7.0

s

155.24ナノ秒

1.00

該当なし

DT_TryFormatInvariant

.NET 8.0

s

15.50ナノ秒

0.10

該当なし








DT_文字列

.NET 7.0

あなた

184.71ナノ秒

1.00

64 B

1.00

DT_文字列

.NET 8.0

あなた

29.62ナノ秒

0.16

64 B

1.00








DT_ToString不変

.NET 7.0

あなた

184.01ナノ秒

1.00

64 B

1.00

DT_ToString不変

.NET 8.0

あなた

26.98ナノ秒

0.15

64 B

1.00








DT_TryFormat

.NET 7.0

あなた

171.73ナノ秒

1.00

該当なし

DT_TryFormat

.NET 8.0

あなた

16.08ナノ秒

0.09

該当なし








DT_TryFormatInvariant

.NET 7.0

あなた

158.42ナノ秒

1.00

該当なし

DT_TryFormatInvariant

.NET 8.0

あなた

15.58ナノ秒

0.10

該当なし








DT_文字列

.NET 7.0

あなた

1,622.28ナノ秒

1.00

1240年

1.00

DT_文字列

.NET 8.0

あなた

206.08ナノ秒

0.13

96 B

0.08








DT_ToString不変

.NET 7.0

あなた

1,567.92ナノ秒

1.00

1240年

1.00

DT_ToString不変

.NET 8.0

あなた

207.60ナノ秒

0.13

96 B

0.08








DT_TryFormat

.NET 7.0

あなた

1,590.27ナノ秒

1.00

1144年

1.00

DT_TryFormat

.NET 8.0

あなた

190.98ナノ秒

0.12

0.00








DT_TryFormatInvariant

.NET 7.0

あなた

1,560.00ナノ秒

1.00

1144年

1.00

DT_TryFormatInvariant

.NET 8.0

あなた

184.11ナノ秒

0.12

0.00

解析にも大きな改善が見られました。たとえば、カスタム書式文字列内の「ddd」(曜日の略称)、「dddd」(曜日の正式名称)、「MMM」(月の略称)、「MMMM」(月の正式名称)の処理が改善されました。これらは、RFC1123 形式の拡張定義(ddd、dd MMM yyyy HH':'mm':'ss 'GMT')など、さまざまな一般的な書式文字列に表示されます。汎用解析ルーチンが書式文字列でこれらに遭遇すると、提供された CultureInfo / DateTimeFormatInfo を参照して、その言語ロケールの関連する月と日の名前 (例: DateTimeFormatInfo.GetAbbreviatedMonthName) を取得し、次に各名前と入力テキストの大文字と小文字を区別しない比較を行う必要があります。これはコストがかかります。ただし、不変の言語ロケールを取得すれば、はるかに高速に実行できます。はるかに高速です。たとえば、「MMM」は月の略称を表します。次の3文字(uint m0 = span[0]、m1 = span[1]、m2 = span[2])を読み取り、それらがすべてASCIIであること((m0 | m1 | m2)<= 0x7F)を確認してから、前に説明したのと同じASCII大文字小文字のトリックを使用して、それらすべてを1つのuintにマージします((m0 << 16)|(m1 << 8)| m2 | 0x202020)。同じことを各月の名前に対して実行できます。これは、事前にわかっている不変のロケールの場合、検索全体が単一の数値スイッチになります。

 switch ((m0 << 16) | (m1 << 8) | m2 | 0x202020) { case 0x6a616e: /* 'jan' */ result = 1; break; case 0x666562: /* 'feb' */ result = 2; break; case 0x6d6172: /* 'mar' */ result = 3; break; case 0x617072: /* 'apr' */ result = 4; break; case 0x6d6179: /* 'may' */ result = 5; break; case 0x6a756e: /* 'jun' */ result = 6; break; case 0x6a756c: /* 'jul' */ result = 7; break; case 0x617567: /* 'aug' */ result = 8; break; case 0x736570: /* 'sep' */ result = 9; break; case 0x6f6374: /* 'oct' */ result = 10; break; case 0x6e6f76: /* 'nov' */ result = 11; break; case 0x646563: /* 'dec' */ result = 12; break; default: maxMatchStrLen = 0; break; // undo match assumption }

エレガントで、はるかに高速です。

 // dotnet run -c Release -f net7.0 --filter "*" --runtimes net7.0 net8.0 using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using System.Globalization; BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args); [HideColumns("Error", "StdDev", "Median", "RatioSD")] [MemoryDiagnoser(displayGenColumns: false)] public class Tests { private const string Format = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"; private readonly string _s = new DateTime(1955, 11, 5, 6, 0, 0, DateTimeKind.Utc).ToString(Format, CultureInfo.InvariantCulture); [Benchmark] public void ParseExact() => DateTimeOffset.ParseExact(_s, Format, CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite | DateTimeStyles.AssumeUniversal); }

パフォーマンス比較:

方法

ランタイム

平均値

比率

配布する

配分比率

パース正確

.NET 7.0

1,139.3ナノ秒

1.00

80 B

1.00

パース正確

.NET 8.0

318.6ナノ秒

0.28

0.00


<<:  GPT-4.5がリーク、3Dビデオをサポート、価格は6倍に上昇?ウルトラマンが自ら反応

>>:  建築環境における人工知能:その可能性を実現するためのステップ

ブログ    
ブログ    
ブログ    
ブログ    
ブログ    
ブログ    

推薦する

世界のトップ25の人工知能企業

過去数年間で人工知能の利用は爆発的に増加しており、すでに多くのスタートアップ企業や大手企業が独自の ...

人工知能は耳の画像だけで年齢と性別を正確に判別できる

画像処理のためのディープラーニング入門:耳のバイオメトリクスは注目の研究トピックとなっている[1]。...

AI産業化が深海域に入る中、コンピューティングパワーのボトルネックをどうやって打破するのか?

AI技術の応用は、一部の業界からあらゆる分野へ、一部のシーンからあらゆるシーンへ、ローカルな探索か...

指紋、顔、虹彩: 適切な生体認証技術を選択するには?

[[351445]]最近、クレジットカード会社からデータ漏洩に関する連絡がありましたか? あるいは...

GitHub CEO: AIアシスタントは同社にとって金のなる木となった

最新のニュースとしては、GitHubのCEOであるThomas Domke氏がメディアとのインタビュ...

...

3D AI が新しい遊び方を生み出します。何時間もかかる代わりに、1 枚の写真からわずか 45 秒で 3D モデルを生成できます。

3D AI生成は近年急速に発展しており、最新の作品の多くは文章・画像から高品質な3Dモデルを生成で...

...

Nature の論文が xAI の目標を検証、人間の認知 AI が宇宙の本質を探る、マスク氏: 黙ってろ、金やるぞ!

馬氏は数日前にAIを使って宇宙の本質を探究することを目的としたAI企業xAIを発表したばかりだ。幸運...

モデルトレーニング: AIと機械学習の最適化とDevOpsツールの利用の改善

フランス料理の秘訣はバター、バター、そしてさらにバターだと言われています。同様に、DevOps の場...

クラウド コンピューティングの 10 年間のベテランが、ディープラーニング手法をゼロから始める

[[206505]]人工知能は現在、熱く議論されている業界であり、ディープラーニングは最もホットな、...

...

スマートビルディングにおけるAIの活用

[[428910]]人工知能は、スマートビルディングパズルの最も重要なピースの 1 つです。これがな...

YouTubeの推奨アルゴリズムは潜在的に有害な動画を優先すると言われている

Mozilla の調査により、YouTube の推奨アルゴリズムは、ヘイトスピーチ、政治的および科学...

...