呼び出し側(RivalDataCsFileCheck.IndeedPlus)で 172 万件規模の CSV を処理した際、 WorkLocation 住所正規化ありで 5224 秒かかった(WorkLocation なし 195 万件では 1671 秒)。
ParseAsync は 1 件ごとに GetCitiesAsync を呼ぶ(AddressService.cs:143)。
GetCitiesAsync(57〜79 行目)は ja.json(約 188 KB、47 都道府県・1898 市区町村)を
毎回ディスクから読み込み・JSON デシリアライズしており、172 万件分繰り返されている。
GetTownsAsync / LoadTownEntriesAsync は ConcurrentDictionary でキャッシュ済みだが、
GetCitiesAsync だけキャッシュが漏れており、実装の一貫性も取れていない。
-
private JaRootResponse? _jaRoot;フィールドを追加する -
LoadJaRootAsync(CancellationToken)ヘルパーメソッドを実装する_jaRootがすでにセットされていればそのまま返す- ない場合は
LoadJsonAsync<JaRootResponse>を呼び_jaRootに格納する
-
GetPrefecturesAsync(35〜51 行目)をLoadJaRootAsync経由に書き換える -
GetCitiesAsync(58〜60 行目)をLoadJaRootAsync経由に書き換える -
AggregateSubCityTownsAsync(337〜338 行目)をLoadJaRootAsync経由に書き換える
-
private readonly ConcurrentDictionary<string, IReadOnlyList<City>> _cityCache = new();
フィールドを追加する(_townCache/_rawEntryCacheと同じ場所・命名規則) -
GetCitiesAsyncにTryGetValue → なければ計算 → 格納のパターンを実装する
(_townCacheの実装パターンに揃えること)
-
dotnet test tests/JaAddress.Core.Tests/がすべてグリーンになること
-
GetPrefecturesAsyncを同一インスタンスで 2 回呼んだとき、返却リストが同一参照(ReferenceEquals)であること -
GetCitiesAsyncを同一都道府県名で 2 回呼んだとき、返却リストが同一参照であること -
ParseAsyncを同一都道府県の異なる住所で複数回呼んだあと、GetCitiesAsyncの
内部呼び出しがキャッシュを使っていること(ファイルI/O が初回 1 回のみに限定されること)
※ ファイル I/O の非発生はモック不要。ReferenceEqualsでキャッシュ済みリストの
同一インスタンス返却を確認することで代替する。
_jaRootはシングルスレッドで初期化されるわけではないが、
GetPrefecturesAsync側の既存ロジック(_prefecturesへの代入)は非スレッドセーフなまま。
_jaRootも同様に「最悪 2 回デシリアライズされても正しい値が返れば問題なし」とする。
_prefecturesの既存パターンを踏襲し、Interlockedやlockは使わない。_cityCacheはスレッドセーフが必要なためConcurrentDictionaryを使うこと。
- 全チェックボックスが完了している
-
dotnet testが全件グリーン(46件) - レビュー・コミット済み