C# ja miljardin rivin haaste, osa 7
Edellisessä blogikirjoituksessa käsittelin neljännen optimoidun version toteutusta, jossa saavutettiin lähinnä takapakkia. Tällä kertaa olisi tarkoitus toteuttaa viides optimoitu versio, joka suurella todennäköisyydellä jää viimeiseksi koodimuokkaukseksi.
PipeReader tekstin lukemiseen
Aiempien toteutusten File-pohjainen tekstirivien lukeminen on tässä toteutuksessa korvattu PipeReader
:in ja SequenceReader
:in yhdistelmällä. Samalla lukeminen on muutettu async-muotoiseksi. Nämä muutokset tekevät koodista selkeästi pidempää, ja samalla myös vaikeammin ymmärrettävää.
Tavujen muuttaminen merkeiksi
Koska aiemmassa toteutuksessa käytössä oleva Encoding.UTF8.GetString
varaa muistia, kun se luo uuden string
-olion, koetin vähentää sen käyttöä. Tässä tapauksessa aiemmin lisätty lookup-toiminto mahdollistaa suoraan ReadOnlySpan<char>
-rakenteen käyttämisen, joten string-olioita ei ole pakko luoda. ASCII-merkkien kanssa tavujen muuttaminen merkeiksi onnistuu vaivattomasti. Esimerkkisyötteessä on kuitenkin kaupunkien nimiä, joissa on muitakin kuin ASCII-merkkejä, joten rajasin nopean muutoksen vain niihin kaupunkien nimiin, jotka sisältävät pelkästään ASCII-merkkejä.
bool useShortCut = false;
if (span.Length <= maybeCityLength)
{
useShortCut = true;
for (int i = 0; i < span.Length; i++)
{
if (span[i] < 127)
{
maybeCity[i] = (char)span[i];
}
else
{
useShortCut = false;
break;
}
}
}
ReadOnlySpan<char> key = useShortCut ? maybeCity.Slice(0, span.Length) : Encoding.UTF8.GetString(span);
Parannus
Edelliseen toteutukseen verrattuna saimme suorituskykyä hieman takaisin, mutta aiempaa .NET 8 -version ennätystä ei saada tällä tavalla kiinni.
Syöte | Oletus (.NET 8) | Optimoitu 1 (.NET 8) | Optimoitu 2 (.NET 8) | Optimoitu 3 (.NET 8) | Optimoitu 3 (.NET 9) | Optimoitu 4 (.NET 9) | Optimoitu 5 (.NET 9) |
---|---|---|---|---|---|---|---|
100 miljoonaa riviä | 38,9 sekuntia | 12,3 sekuntia | 8,0 sekuntia | 5,7 sekuntia | 6,3 sekuntia | 6,3 sekuntia | 6,1 sekuntia |
1 miljardi riviä | Muisti loppuu | 114,5 sekuntia | 78,2 sekuntia | 54,6 sekuntia | 60,9 sekuntia | 62,7 sekuntia | 60,0 sekuntia |
Tulossa
Seuraavaksi luvassa on kooditon muutos, eli koetamme tehdä ohjelmasta AOT-binäärin, ja katsomme nopeuttaako se ohjelman suoritusta
📊