Daftar tambahan hanya C# yang tidak dapat diubah dan berkecepatan tinggi. (pembaruan: 23 Sep 24; tidak disarankan untuk digunakan. Lihat catatan di bawah untuk alasan dan alternatif.)
dotnet tambahkan paket AppendOnly
Pertama, koleksi yang sudah ada dan tidak dapat diubah mengalami kesulitan untuk memungkinkan Anda melakukan penambahan, penghapusan, dan pembaruan yang mengembalikan koleksi baru. Mereka benar-benar HARUS menyalin banyak hal. Jika Anda hanya menambahkan, LinkedList adalah teman Anda, dan tampak seperti "disalin" secara instan.
Kedua, perpustakaan abadi yang ada bersifat kompleks dan sulit digunakan. Mereka memerlukan kelas pembangun dan pemahaman yang baik tentang mekanisme sebenarnya, jika tidak, Anda akan mengalami masalah kinerja yang sangat buruk.
Terakhir: Kelas ini benar-benar aman untuk digunakan dalam loop yang sangat ketat. Seperti dalam, seketat yang Anda bisa.
AppendOnly menggunakan A linkedList secara internal, dan tidak pernah menyalin item koleksi saat membuat salinan baru yang "tidak dapat diubah". Ini hanya mengembalikan kelas koleksi baru yang berbagi linkedList internal yang "dapat diubah", tetapi tidak mengekspos metode apa pun untuk mengubahnya, hanya mengekspos interator yang melakukan iterasi melalui (n) item pertama dalam koleksi.
Jadi ketika koleksi bertambah besar, instance kelas koleksi sebelumnya (yang lebih lama), tidak akan pernah melihat (mengekspos melalui enumerator) entri baru yang ditambahkan ke akhir daftar. Setelah menambahkan 1000 "transaksi" baru ke appendOnly TransactionCollection, Anda secara efektif memiliki (jika Anda menyimpan referensi ke setiap koleksi yang baru dibuat) 1000 pointer ke koleksi yang masing-masing berisi, 1, 2, 3, 4 item dll, tetapi dengan hampir nol tambahan memori di atas kepala.
Jika menggunakan perpustakaan abadi lainnya dengan pembuat, sebagian besar dari mereka akan memberi Anda minimal 500.000 contoh objek.
Saya mungkin salah, ini adalah titik awal, beri tahu saya jika Anda menggunakan ini. Saya akan membuat lebih banyak koleksi dengan cara yang sama.
var move = new AppendOnlyList<Moves>();var new_moves = new AppendOnlyList<Moves>();Debug.Assert(moves.Length == 0);// tambahkan 10 gerakan acak for(int i=0; i<10 ; i++) new_moves = new_moves.Add(randomMove());// gerakan asli masih belum memiliki item meskipun new_list telah menambahkan item ke List.Debug.Assert(moves.Length == 0);// new_list memiliki 10 item dalam collectionDebug.Assert(new_moves.Length == 10);// daftar ini aman untuk diulang berkali-kali dan aman untuk thread// kode di bawah ini menunjukkan perulangan ke seluruh daftar sepuluh kali, sesuatu yang biasanya hanya Anda lakukan terhadap// enumerable jika Anda telah menyimpannya dalam cache, yaitu membuat salinan lokal.// Saya tahu ini sepertinya tidak memberikan banyak manfaat, tetapi ini sangat penting. // juga, aman untuk melakukan ini SAAT thread lain sedang sibuk menambah koleksi dasar yang sama, // sesuatu yang sangat TIDAK DILAKUKAN di dunia threading. Di sini, sepenuhnya aman.for(int i = 0; i<10; i++){foreach(var move in new_moves.Items) menunggu DoSomethingFunkyAsync(move);}
Dalam kode di atas, new_moves
dan moves
asli berbagi daftar tertaut dasar yang sama. Ketika salinan baru dari AppendOnlyList dibuat, TIDAK ada klon baru yang dibuat, hanya satu titik ke bagian atas daftar dan Panjangnya dipertahankan.
Ini SANGAT CEPAT, karena, TIDAK ADA SALINAN yang dibuat, jadi ini jauh lebih cepat daripada koleksi abadi lainnya yang membuat salinan.
Dan aman untuk mengulangi koleksi SAAT sedang dihitung dari thread lain! LEDAKAN! ... atau lebih khusus lagi "tidak ada Boom!".
ini adalah versi 0.1.3
yang artinya belum siap untuk penggunaan produksi. Ini adalah bukti konsep, dan saya perlu menulis beberapa tes threading untuk membuktikan klaim di atas, dan kemudian meminta rekan-rekan saya untuk meninjau dan memberi tahu saya.
Saya juga ingin melakukan perbandingan kecepatan antara koleksi ini dan koleksi lainnya serta perbandingan berdampingan.
jika Anda menyukai paket ini, lihat implementasi sebenarnya yang terdiri dari 2 kelas, AppendOnlyList
dan LinkedListExtensions
, dan ukurannya kecil.
beri tahu saya pendapat Anda?
:D
Ada pertanyaan, hubungi saya di,
Alan Hemmings, twitter : @snowcode LinkedIn : https://www.linkedin.com/in/goblinfactory www : https://goblinfactory.co.uk
...dan tidak banyak menggunakannya, dan yah, lupakan saja. Banyak hal (C#) telah berubah sejak saya menulis ini, dan meskipun ada banyak perubahan dalam C#, tidak ada satupun yang benar-benar menyederhanakan banyak hal. Sayangnya menurut saya pemikiran saya di atas, tentang kapan menggunakan paket ini, mengingat adanya perubahan bahasa baru, mungkin hanya sampah, dan mungkin...sangat salah. Tes PASTI diperlukan sebelum melakukan sesuatu lebih jauh. Berikut beberapa catatan dari obrolan singkat dengan Arsitek AI C#, yang menyarankan revisi terhadap proyek ini. TBH Saya pikir proyek ini mungkin masih diperlukan, tetapi mungkin sebagai pembungkus DSL (semacam kelas pabrik sederhana) di sekitar berbagai cara untuk membuat struktur tipe pelengkap dengan benar. Nuff berkata; inilah tanggapannya;
(draf catatan, perlu diuji, dan dikonfirmasi!)
Ya, di C#, Anda dapat menggunakan System.Collections.Generic.ArrayBuffer<T>
atau System.Buffers.ArrayPool<T>
untuk struktur tambahan yang lebih efisien dan hemat memori yang dapat dihitung secara efisien. Namun, jika Anda menginginkan struktur tambahan saja yang lebih praktis dan efisien, pertimbangkan opsi berikut:
ImmutableArray<T>.Builder
Struktur tambahan saja yang disediakan oleh paket System.Collections.Immutable
.
Hal ini memungkinkan penambahan yang efisien dan dapat diubah saat membangun, namun menjadi tidak dapat diubah setelah dikonversi ke ImmutableArray<T>
.
var pembangun = ImmutableArray.CreateBuilder<int>();builder.Add(1);builder.Add(2);var immutableArray = pembangun.ToImmutable();
Memory<T>
dan Span<T>
dengan ArrayPool<T>
Efisien untuk menangani blok data besar dengan alokasi memori minimal.
Anda mengelola memori sendiri, sehingga menghindari realokasi yang sering dibandingkan dengan List<T>
.
Cocok jika Anda ingin kontrol lebih besar atas penggunaan memori namun memerlukan pengelolaan yang cermat.
var pool = ArrayPool<int>.Berbagi;int[] array = pool.Rent(1000); // Minta array dari pool// Tambahkan dan kelola data Anda di sinipool.Return(array); // Kembali ke kolam setelah selesai
ValueListBuilder<T>
(Dari System.Buffers)
Menyediakan cara yang efisien untuk membangun koleksi dengan cara yang dialokasikan dalam tumpukan.
Sangat berguna ketika Anda mengetahui ukuran data dibatasi dan menginginkan performa tinggi tanpa alokasi tumpukan.
Rentang<int> inisialSpan = stackalloc int[16]; var valueListBuilder = ValueListBuilder baru<int>(initialSpan);valueListBuilder.Append(1);valueListBuilder.Append(2);ReadOnlySpan<int> span = valueListBuilder.AsSpan();
Sequence<T>
dari System.IO.Pipelines
Cocok untuk menangani urutan data secara efisien dengan cara tambahan saja.
Cocok untuk skenario yang memerlukan operasi I/O performa tinggi dan streaming data.
List<T>
: Baik untuk menambahkan (diamortisasi O(1)
) dan menyediakan enumerasi cepat karena memori yang berdekatan.
ImmutableArray<T>.Builder
: Efisien untuk menambahkan dan kemudian menjadikannya tidak dapat diubah.
Memory<T>
dengan ArrayPool<T>
: Bagus untuk mengurangi alokasi.
ValueListBuilder<T>
: Bangunan berbasis tumpukan yang efisien ketika ukurannya diketahui. Berbasis tumpukan, cocok untuk pengumpulan sementara dan efisien.
Sequence<T>
: Untuk skenario throughput tinggi yang memerlukan penambahan efisien.
Pilih berdasarkan kinerja spesifik dan kebutuhan memori Anda.
ChatGPT berkata;
LinkedList<T>
di C# adalah opsi untuk struktur memori tambahan saja, namun umumnya kurang hemat memori dan lebih lambat untuk enumerasi dibandingkan dengan struktur lain karena alasan berikut:
LinkedList<T>
: Memory Overhead : Setiap node dalam LinkedList<T>
berisi referensi ke node berikutnya dan sebelumnya, yang menimbulkan overhead memori yang signifikan dibandingkan dengan struktur yang berdekatan seperti array atau List<T>
.
Inefisiensi Cache : Tidak seperti array atau List<T>
yang disimpan dalam memori yang berdekatan, node LinkedList<T>
tersebar di seluruh heap. Hal ini membuatnya kurang ramah terhadap cache, sehingga memperlambat iterasi dan waktu akses.
Kinerja Pencacahan : Meskipun LinkedList<T>
efisien untuk operasi penambahan ( O(1)
untuk penambahan di akhir), kinerja pencacahannya biasanya lebih lambat dibandingkan array atau daftar karena tidak memiliki keunggulan lokalitas cache.
LinkedList<T>
:Ketika Anda perlu sering memasukkan atau menghapus di kedua ujung atau di tengah.
Jika Anda ingin menghindari perpindahan elemen seperti di List<T>
.
LinkedList<T>
dapat digunakan untuk skenario tambahan saja tetapi umumnya bukan pilihan paling efisien untuk enumerasi atau penggunaan memori dibandingkan dengan List<T>
atau struktur data modern lainnya.