.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倍に上昇?ウルトラマンが自ら反応

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

ブログ    
ブログ    
ブログ    

推薦する

...

OpenAIがMicrosoftに反旗を翻す!アルトマン氏が「ChatGPTのカスタマイズ」を企む。AI市場の未来はまた変わるのか?

ChatGPTはリリースからわずか半年で、5日間でユーザー数が100万人を超え、現在ユーザー総数は...

IoTとAI: この強力な組み合わせの5つの興味深い応用

人工知能は現代世界のあらゆる分野を征服しつつあります。しかし、それらはすべて私たちにとって良いことな...

Huyaは人間とシーンの分離技術を使用して、顔を覆わずにスマートな弾丸スクリーンを作成します

【元記事は51CTO.comより】 「(段)幕」という言葉はシューティングゲームから生まれたもので、...

データの筒状のビジョンを避け、人間と機械の調和のとれた共生関係を築く

​​​ [51CTO.com クイック翻訳]比較するためのより良い座標系がないため、人間がよく犯す間...

...

オリンピックチャンピオンでさえ正しく答えられなかった質問が ML モデルのテストに使用されているのですか? GPT-3: できない

機械学習モデルの数学解答能力を測定するために、カリフォルニア大学バークレー校とシカゴ大学の研究者らは...

3Dの名の下、「インテリジェント製造」の包囲はAIビジョンユニコーンの新たな戦場です

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式...

ソフトマックスボトルネックを超えて: 高ランク RNN 言語モデル

因数分解に基づいて、リカレントニューラルネットワーク (RNN) に基づく言語モデルは、複数のベンチ...

...

なぜ巨人たちはドローンに群がるのか?

近年、我が国のドローン産業は急速な発展を遂げています。飛行制御、ナビゲーション、通信、センシングなど...

警察が採用したボストン・ダイナミクスの犬たちは、感情のない「監視ツール」になるのだろうか?

[[384524]]ニューヨークのマンハッタン北部のアパートで男性2人が人質に取られている。その数...

アルゴリズムによるレイオフによって解き放たれる「悪の花」とは?

アルゴリズムによる採用は珍しいことではありません。膨大な履歴書の審査を自動化するために AI アルゴ...

人工知能技術は人間の生活にどのような影響を与えるのでしょうか?

[[349271]]人工知能と産業の組み合わせは、中国市場の爆発的な成長を促進し、中国のモバイルイ...

Googleの研究者が自撮りカメラ用の顔歪み防止アルゴリズムを開発

最近の調査によると、毎日 9,300 万枚の自撮り写真がソーシャル メディアに投稿されており、Ins...