Ucapkan kata yang buruk untuk LINQ

Sepanjang hidup saya sebagai programmer c #, saya berpikir bahwa LINQ bukan terutama tentang kinerja kode, tetapi tentang kinerja programmer, seberapa cepat ia menulis kode, dan bukan seberapa cepat prosesor menjalankan kode ini. Dan masalah kinerja kedua kode dan programmer diselesaikan setelah mengidentifikasi kemacetan. Karenanya, saya sering menulis var groupedByDate = lst.GroupBy(item => item.IssueTime.Date).Select(…).ToList()dan melakukan ini bukan karena niat jahat atau jahat, tetapi lebih mudah untuk men-debug kode. Untuk daftar, cukup letakkan kursor mouse di atas teks variabel dan Anda dapat segera melihat apakah ada sesuatu di sana atau tidak.


Mulailah


Setelah membaca artikel "Artikel gagal tentang percepatan refleksi " dan menenangkan emosi tentang "seseorang salah di Internet", saya bertanya-tanya apakah mungkin untuk membuat "LINQ to Objects" kode dekat dalam kinerja menjadi "manual". Mengapa tepatnya LINQ to Objects? Dalam pekerjaan saya, saya sering hanya menggunakan LINQ untuk Objects dan LINQ untuk penyedia Entitas. Kinerja LINQ untuk Entitas tidak penting bagi saya; sangat penting seberapa optimal query SQL yang dihasilkan untuk server database target dan seberapa cepat server akan menjalankannya.


Sebagai dasar, saya memutuskan untuk menggunakan proyek penulis artikel. Berbeda dengan contoh-contoh dari Internet, di mana suatu kode terutama dibandingkan seperti integerList.Where(item => item > 5).Sum()kode "manual" yang berisi foreach, ifdan seterusnya, contoh dari artikel itu tampak menarik dan vital bagi saya.


Hal pertama yang saya lakukan adalah menggunakan fungsi perbandingan string tunggal. Dalam kode sumber, dalam metode yang melakukan fungsi yang sama, tetapi terletak di sudut berlawanan dari cincin, metode yang berbeda digunakan, dalam satu kasus variable0.Equals(constant0, StringComparison.InvariantCultureIgnoreCase)dan yang lain variable0.ToUpperInvariant() ==constant0.ToUpperInvariant(). Ini sangat menjengkelkan untuk konstanta bahwa setiap pemanggilan metode dikonversi ke huruf besar. Saya memilih opsi ketiga menggunakan dalam kedua kasus variable0.ToUpperInvariant() ==constant0InUpperCaseInvariant.


Kemudian semua kode yang tidak terkait langsung dengan membandingkan kinerja LINQ dan kode manual dibuang. Yang pertama ditangkap adalah kode yang membuat dan menginisialisasi objek kelas Mock<HabraDbContext>. Apa gunanya membuat koneksi database untuk setiap tes, sekali sudah cukup? Itu telah dipindahkan melampaui tes kinerja.


IStorage _db;

[GlobalSetup]
public void Setup()
{
    _db = MockHelper.InstanceDb();
}

private IStorage DBInstance => _db;

… — , ! Linq «» !


gambar


« - » . LINQ . , — .



, , LINQ vs «» . . . .


, , , ([Params(1, 10, 100, 1000)]). . . . StatisticColumnRelStdDev.


FastHydrationLinq, ManualHydrationLinq — . , , (Fast)(Manual)(Slow)HydrationLinq vs (Fast)(Manual)(Slow)Hydration, ManualHydrationLinq. FastHydrationLinq - . .


ToArray, ToDictionary IEnumerable<T> . , FastContactHydrator2. - Action<Contact, string> c ConcurrentDictionary<string, Action<Contact, string>> IEnumerable<KeyValuePair<string, Action<Contact, string>>>. GetContact2, Sum, .


protected override Contact GetContact2(IEnumerable<PropertyToValueCorrelation> correlations)
{
    var contact = new Contact();
    int dummySum = _propertySettersArray.Join(correlations, propItem => propItem.Key, corrItem => corrItem.PropertyName, (prop, corr) => { prop.Value(contact, corr.Value); return 1; }).Sum();
    return contact;
}

ParseWithLinq


public static IEnumerable<KeyValuePair<string, string>> ParseWithLinq2(string rawData, string keyValueDelimiter = ":", string pairDelimiter = ";")
    => rawData.Split(pairDelimiter)
    .Select(x => x.Split(keyValueDelimiter, StringSplitOptions.RemoveEmptyEntries))
    .Select(x => x.Length == 2 ? new KeyValuePair<string, string>(x[0].Trim(), x[1].Trim())
                                : new KeyValuePair<string, string>(_unrecognizedKey, x[0].Trim()));

.


FastContactHydrator2, , , , -, ( ParseWithLinq ParseWithoutLinq). . , , ToArray. 10 var result = new List<PropertyToValueCorrelation>(10). 10? 42 , 10 . Fair .


. . GetFakeData . , .
, , « » (RelStdDev). N=1000.


:


-  `ManualHydration`, `SlowHydration`, `FastHydration`, `ManualHydrationLinq`, `SlowHydrationLinq`, `FastHydrationLinq` -     ,  ;

  • ManualHydrationFair, ManualHydrationFairLinq, FastHydrationFairLinq — , ;
  • FastHydrationLinq2 — , , - , LINQ;
  • N , ;
  • Ratio FastHydrationLinq2.

gambar
Linq-


? — FastHydrationLinq2 ManualHydrationLinq Ratio. 26,361.37 μs 26,422.17 μs N=1000. / N. ManualHydrationFairLinq, 8% , . FastHydrationFairLinq, 1% -.


Fair-. , ManualHydrationFairLinq 8% . FastHydrationFairLinq FastHydrationLinq 12%. Linq .


, . . , MockHelper.InstanceDb() Setup, . — , GetFakeData, . , — . MockHelper.InstanceDb() .


N, MakeGarbage. False , True — .


gambar


N

image


Voilà, , . — N=1. 10% 82% .


… .



, , «» — Linq-, :


gambar
N=1 MakeGarbage=True «»


, , , LINQ .
«Gen X» «Allocated» N=1 MakeGarbage=True o , FastHydrationLinq2


|                                |      Gen 0 |   Gen 1 | Gen 2 |   Allocated |
|«»     |    20.5078 |  0.4883 |     - |    63.95 KB |
|Linq-        |    20.7520 |       - |     - |    63.69 KB |

ManualHydrationFairLinq .


. , , — .
, ? . , N [Params(1, 100)] MakeGargabe=True. «» — Linq-, . — , — Linq-, Linq — — — Linq. — . .


, , — Linq- . , . paint.net, . paint.net — paint.net . paint.net — «» , — Linq- .


N 1, 10, 100, 1000 MakeGarbage [ParamsAllValues]. paint.net, — «» . — Linq- . paint.net Visual Studio — «» . , 80- . , Linq- 2%.



Setelah menulis tes dan menganalisis hasilnya, pendapat saya tentang LINQ tidak berubah - menggunakannya produktivitas saya dalam menulis kode lebih tinggi daripada tanpa itu; Kinerja LINQ to Objects baik-baik saja. Menggunakan eksekusi kode LINQ yang tertunda sebagai cara meningkatkan kinerja tidak masuk akal.


Jika dalam suatu proyek ada masalah kinerja karena pengumpul sampah - cedera lahir bersih, maka mungkin memilih teknologi ini bukan solusi terbaik.


Kode pengujian saya tersedia di sini .


All Articles