Dalam kasus di mana bacaan jauh lebih banyak daripada menulis, atau (betapapun sering) menulis tidak bersamaan , copy-on-write mungkin tepat.
Implementasi yang ditunjukkan di bawah ini adalah
- tidak terkunci
- sangat cepat untuk membaca bersamaan , bahkan saat modifikasi bersamaan sedang berlangsung - tidak peduli berapa lama waktu yang dibutuhkan
- karena "snapshots" tidak dapat diubah, atomicity tanpa kunci adalah mungkin, yaitu
var snap = _list; snap[snap.Count - 1];
tidak akan pernah (yah, kecuali untuk daftar kosong tentu saja) melempar, dan Anda juga mendapatkan pencacahan aman dengan semantik snapshot gratis .. bagaimana saya MENCINTAI kekekalan!
- diimplementasikan secara umum , berlaku untuk setiap struktur data dan semua jenis modifikasi
- sederhana , yaitu mudah untuk menguji, men-debug, memverifikasi dengan membaca kode
- dapat digunakan dalam. Net 3.5
Agar copy-on-write berfungsi, Anda harus menjaga agar struktur data Anda tetap tidak dapat diubah , yaitu tidak ada seorang pun yang boleh mengubahnya setelah Anda membuatnya tersedia untuk utas lainnya. Ketika Anda ingin memodifikasi, Anda
- mengkloning struktur
- melakukan modifikasi pada klon
- bertukar atom dalam referensi ke klon yang dimodifikasi
Kode
static class CopyOnWriteSwapper
{
public static void Swap<T>(ref T obj, Func<T, T> cloner, Action<T> op)
where T : class
{
while (true)
{
var objBefore = Volatile.Read(ref obj);
var newObj = cloner(objBefore);
op(newObj);
if (Interlocked.CompareExchange(ref obj, newObj, objBefore) == objBefore)
return;
}
}
}
Pemakaian
CopyOnWriteSwapper.Swap(ref _myList,
orig => new List<string>(orig),
clone => clone.Add("asdf"));
Jika Anda memerlukan lebih banyak kinerja, ini akan membantu untuk menghilangkan metode, misalnya membuat satu metode untuk setiap jenis modifikasi (Tambah, Hapus, ...) yang Anda inginkan, dan hard code pointer fungsi cloner
dan op
.
NB # 1 Adalah tanggung jawab Anda untuk memastikan tidak ada yang mengubah struktur data (yang seharusnya) tidak dapat diubah. Tidak ada yang bisa kita lakukan dalam implementasi generik untuk mencegah hal itu, tetapi ketika mengkhususkan diri untuk List<T>
, Anda bisa menjaga terhadap modifikasi menggunakan List.AsReadOnly ()
NB # 2 Berhati-hatilah dengan nilai-nilai dalam daftar. Pendekatan salin saat menulis di atas hanya melindungi keanggotaan daftar mereka, tetapi jika Anda tidak meletakkan string, tetapi beberapa objek yang dapat berubah di sana, Anda harus menjaga keamanan utas (mis. Mengunci). Tapi itu ortogonal untuk solusi ini dan misalnya penguncian nilai-nilai yang bisa berubah dapat dengan mudah digunakan tanpa masalah. Anda hanya perlu menyadarinya.
NB # 3 Jika struktur data Anda sangat besar dan Anda sering memodifikasinya, pendekatan copy-all-on-write mungkin menjadi penghalang baik dalam hal konsumsi memori maupun biaya penyalinan CPU yang terlibat. Dalam hal itu, Anda mungkin ingin menggunakan Koleksi Immutable MS sebagai gantinya.