Lühike sissejuhatus
Jõudluse optimeerimine on viis, kuidas tagada, et sama arv päringuid töödeldakse vähemate ressurssidega, mis on tavaliselt CPU või mälu, ning muidugi operatsioonisüsteemi IO käepidemed, võrguliiklus, kettakasutus jne. Kuid enamasti vähendame protsessori ja mälu kasutust. Varem jagatud sisul on mõned piirangud, seda on raske otse teisendada, täna tahan teiega jagada lihtsat meetodit, kus tuleb vaid mõned kogumitüübid asendada, et saavutada jõudluse paranemise ja mälu mahu vähendamise efekt. Täna tahan teiega jagada klassi raamatukogu, sedaKlassi raamatukogu kannab nime Kogud. Ühised, Nagu nimest näha, kasutatakse seda ühendatud mälu kaudu, et vähendada mälu jalajälje ja GC-d, ning me vaatame otse, kuidas selle jõudlus on, ning viime teid ka lähtekoodi juurde, miks see toob kaasa jõudluse paranemise.
Kogud. Ühised
Projekti link:Hüperlingi sisselogimine on nähtav.
Raamatukogu põhineb System.Collections.Generic'i klassidel, mida on muudetud, et kasutada uusi System.Span <T>ja System.Buffers.ArrayPool <T>klassiteeke, et vähendada mälu jaotust, parandada jõudlust ja võimaldada suuremat ühilduvust kaasaegsete API-dega. Collections.Pooled toetab .NET Standnd 2.0 (.NET Framework 4.6.1+) ning samuti . NET Core 2.1+. CoreFX-ist on üle toodud ulatuslik hulk ühikuteste ja teste.
Testide koguarv: 27501. Allikas: 27501. Ebaõnnestumine: 0. Skip: 0. Katsetus oli edukas. Testi täitmise aeg: 9,9019 sekundit
Kuidas kasutada
Selle teegi saab hõlpsasti paigaldada Nugeti kaudu, NuGet Version.
Collections.Pooled teegis rakendatakse kogumitüüpide jaoks kogutud versioone, mida tavaliselt kasutame, nagu näitab võrdlus .NET natiivsete tüüpidega.
| . .NET natiivne | Kogud. Ühised | Märkus | | Loend<T> | PooledList<T> | Üldised kollektsiooniklassid | | Sõnaraamat<TKey, TValue> | PooledDictionary<TKey, TValue> | Üldine sõnastiku klass | | HashSet<T> | PooledSet<T> | Üldised räsi kogumise klassid | | Pinu<T> | Pinu<T> | Üldised virnad | | Järjekorda<T> | PooledQueue<T> | Üldine kohort |
Kasutades tuleb lisada ainult vastav . .NET natiivse versiooni koos Collections.Pooled versiooniga, nagu on näidatud allolevas koodis:
Siiski tuleb märkida, et Pooled tüüp rakendab IDispose liidest, mis tagastab kasutatud mälu Basse'ile Dispose() meetodi kaudu, seega peame pärast Pooled kollektsiooniobjekti kasutamist kutsuma selle Dispose() meetodi. Või võid kasutada otse märksõna "using var".
Märkus: Kasuta kogu objekti Collections.Pooled seesParim on see käsitsi vabastada, aga pole vahet, kui sa seda ei vabasta, GC taaskasutab selle lõpuks, aga seda ei saa basseini tagasi tuua ja mälu säästmise efekti ei saavuta. Kuna mäluruumi taaskasutatakse, peab ta mäluruumi tagastamisel töötlema kogumi elemente ning pakub kasutamiseks nimega ClearMode, mis on määratletud järgmiselt:
Vaikimisi saad kasutada vaikimisi väärtust Auto ning kui on erilised jõudlusnõuded, saad kasutada Never'i pärast riskide teadmist. Viitetüüpide ja väärtustüüpide puhul, mis sisaldavad viitetüüpe, peame massiivi viite tühjendama, kui tagastame mäluruumi basseini; kui seda ei puhastata, ei saa GC seda osa mäluruumist vabastada (sest elemendi viide on alati olnud basseinis), kui tegemist on puhta väärtuse tüübiga, siis seda ei saa tühjendada. Selles artiklis kirjeldan salvestuse erinevust viitetüüpide ja struct (väärtuse tüübi) massiivide vahel, puhtad väärtustüübid ei oma objektipäise taaskasutust ega vaja GC sekkumist.
. .NET jõudluse optimeerimine – Kasuta struct alternatiivseid klasse:Hüperlingi sisselogimine on nähtav.
Jõudluse võrdlus
Ma ei teinud Benchmarki üksi ja avatud lähtekoodiga projektide jooksutulemused, mida ma otseselt kasutasin, olid paljude projektide mälukasutuse kohta 0, mis oli tingitud sellest, et kasutatud ühismälul polnud lisajaotust.
PooledList<T>
Vaata Benchmarkis komplekti lisatud 2048 elementi, . .NET natiivne List <T>nõuab 110us (vastavalt tegelikele võrdlustulemustele peaksid joonisel olevad millisekundid olema kirjaviga) ja 263KB mälu, samas kui PooledList <T>vajab ainult 36us ja 0KB mälu.
PooledDictionary<TKey, TValue>
Lisa sõnaraamatusse 10_0000 elementi tsüklis Benchmarkis, . .NET natiivse sõnastik<TKey, TValue> nõuab 11ms ja 13MB mälu, samas kui PooledDictionary<TKey, TValue> vajab vaid 7ms ja 0MB mälu.
PooledSet<T>
Läbi Benchmarki räsikogu, lisa 10_0000 elementi, . .NET natiivse HashSet <T>nõuab 5348ms ja 2MB, samas kui PooledSet <T>vajab vaid 4723ms ja 0MB mälu.
PooledStack<T>
Tee Benchmarkis virna läbi, et lisada 10_0000 elementi, . .NET natiivse PooledStack <T>vajab 1079ms ja 2MB, samas kui PooledStack <T>vajab vaid 633 ms ja 0 MB mälu.
PooledQueue<T>
Tee Benchmarkis tsüklite läbi, et lisada järjekorda 10_0000 elementi, . .NET natiivse <T>PooledQueue nõuab 681ms ja 1MB, samas kui PooledQueue <T>vajab vaid 408ms ja 0MB mälu.
Stseeni ei avaldata käsitsi
Lisaks mainisime eespool, et kogutud kollektsioonitüüp tuleb vabastada, kuid pole vahet, kas seda ei vabastata, sest GC taaskasutab.
Võrdlusindeksi tulemused on järgmised:
Järeldus võib teha ülaltoodud võrdlustulemustest.
Pooled tüüpi kollektsiooni vabastamine õigeaegselt käivitab vaevu GC-d ja eraldab mälu, ülaltoodud graafiku järgi eraldab mälu vaid 56 baiti. Isegi kui Pooled tüüpi kollektsiooni ei vabastata, sest see eraldab mälu basseinist, kasutab see mälu ReSize laienduse ajal ja jätab GC eraldatud mälu initsialiseerimise etapi vahele, mis on suhteliselt kiire. Kõige aeglasem on kasutada tavalist kogumistüüpi, iga ReSize laiendusoperatsioon peab rakendama uut mäluruumi ning GC peab samuti tagasi võtma eelmise mäluruumi.
Põhimõtteanalüüs
Kui oled lugenud minu eelmist blogipostitust, siis peaksid määrama kogumitüüpide algsuuruse ja analüüsima C# sõnastiku rakenduspõhimõtet, tead, et .NET BCL arendajad kasutavad nende põhiliste kogumitüüpide aluseks olevaid andmestruktuure kõrge jõudlusega juhusliku ligipääsu massiividena, võtame näiteks <T>Listi.
Loo uus massiivi lisatud elementide salvestamiseks. Kui massiivis pole piisavalt ruumi, käivitatakse laiendusoperatsioon, et taotleda kahekordset ruumi suurust. Konstruktorkood on järgmine ning näete, et tegemist on otse generilise massiiviga:
Kui tahad mälu koguda, pead muutma ainult kohta, kus uus märksõnarakendus klassiraamatukogus asub, et kasutada pooled rakendust. Siin jagan seda sinuga. NET BCL on tüüp nimega ArrayPool, mis pakub massiivi ressursikogumit korduvkasutatavatest üldistest eksemplaridest, mida saab kasutada GC surve vähendamiseks ja jõudluse parandamiseks sagedase massiivi loomise ja hävitamise korral.
Meie Pooled tüübi aluskiht on kasutada ArrayPooli ressursibasseinide jagamiseks ning selle konstruktorist näeme, et ta kasutab vaikimisi <T>ArrayPooli. Jagatud massiiviobjektide määramiseks ja loomulikult saad luua ka oma ArrayPooli selle kasutamiseks.
Lisaks, kui tehakse mahu reguleerimise operatsiooni (laiendus), tagastatakse vana massiiv lõimepooli ning uus massiiv võetakse samuti basseinist.
Lisaks kasutab autor Spani, et optimeerida API-sid nagu Add ja Insert, et pakkuda paremat juhusliku juurdepääsu jõudlust. Lisaks on lisatud TryXXX seeria API, nii et seda saab mugavamalt kasutada. Näiteks on Listi <T>klassil <T>kuni 170 modifikatsiooni võrreldes PooledListiga.
Kokkuvõte
Meie tegelikus veebikasutuses saame asendada natiivse kollektsioonitüübi Pooled'i pakutava kollektsioonitüübiga, mis on väga kasulik mälukasutuse ja P95 latentsuse vähendamisel. Samuti, isegi kui unustad selle välja anda, ei ole jõudlus palju halvem kui natiivse kollektsioonitüübi kasutamisel. Muidugi on parim harjumus see õigel ajal vabastada.
Originaal:Hüperlingi sisselogimine on nähtav.
|