Legalitas implementasi COW std :: string di C ++ 11

117

Menurut pemahaman saya, copy-on-write bukanlah cara yang layak untuk mengimplementasikan kepatuhan std::stringdalam C ++ 11, tetapi ketika muncul dalam diskusi baru-baru ini saya mendapati diri saya tidak dapat secara langsung mendukung pernyataan itu.

Apakah saya benar bahwa C ++ 11 tidak menerima implementasi berbasis COW std::string?

Jika ya, apakah batasan ini secara eksplisit dinyatakan di suatu tempat dalam standar baru (di mana)?

Atau apakah pembatasan ini tersirat, dalam arti bahwa itu adalah efek gabungan dari persyaratan baru std::stringyang menghalangi implementasi berbasis KK std::string. Dalam hal ini, saya akan tertarik pada gaya bab dan ayat derivasi dari 'C ++ 11 secara efektif melarang std::stringimplementasi berbasis COW '.

acm
sumber
5
Bug GCC untuk string COW mereka adalah gcc.gnu.org/bugzilla/show_bug.cgi?id=21334#c45 . Salah satu bug yang melacak implementasi kompilasi C ++ 11 baru dari std :: string di libstdc ++ adalah gcc.gnu.org/bugzilla/show_bug.cgi?id=53221
user7610

Jawaban:

120

Itu tidak diperbolehkan, karena sesuai standar 21.4.1 p6, pembatalan iterator / referensi hanya diperbolehkan untuk

- sebagai argumen untuk fungsi pustaka standar apa pun yang menggunakan referensi ke non-const basic_string sebagai argumen.

- Memanggil fungsi anggota non-const, kecuali operator [], di, depan, belakang, mulai, rbegin, akhir, dan rend.

Untuk string COW, memanggil non-const operator[]akan memerlukan pembuatan salinan (dan referensi yang tidak valid), yang tidak diizinkan oleh paragraf di atas. Oleh karena itu, tidak lagi legal untuk memiliki string COW di C ++ 11.

Dave S
sumber
4
Beberapa alasan: N2534
MM
8
-1 Logika tidak menahan air. Pada saat penyalinan KK tidak ada referensi atau iterator yang dapat dibatalkan, inti dari melakukan penyalinan adalah bahwa referensi atau iterator tersebut sekarang sedang diperoleh, jadi penyalinan diperlukan. Tapi mungkin C ++ 11 masih melarang implementasi COW.
Cheers and hth. - Alf
11
@ Cheersandhth.-Alf: Logikanya dapat dilihat pada berikut ini jika KK diperbolehkan: std::string a("something"); char& c1 = a[0]; std::string b(a); char& c2 = a[1]; c1 mengacu pada a. Anda kemudian "menyalin" a. Kemudian, saat Anda mencoba mengambil referensi untuk kedua kalinya, referensi tersebut harus membuat salinan untuk mendapatkan referensi non-const karena ada dua string yang mengarah ke buffer yang sama. Ini harus membatalkan referensi pertama yang diambil, dan bertentangan dengan bagian yang dikutip di atas.
Dave S
9
@ Cheersandhth.-Alf, menurut ini , pelaksanaan SAPI setidaknya GCC tidak melakukan persis apa yang Daves katakan. Jadi setidaknya jenis KK itu dilarang oleh standar.
Tavian Barnes
4
@Alf: Jawaban ini menyatakan bahwa non-const operator[](1) harus membuat salinan dan (2) ilegal untuk melakukannya. Manakah dari dua poin itu yang tidak Anda setujui? Melihat komentar pertama Anda, tampaknya sebuah implementasi dapat membagikan string tersebut, setidaknya di bawah persyaratan ini, hingga saat itu diakses, tetapi akses baca dan tulis harus tidak membagikannya. Apakah itu alasan Anda?
Ben Voigt
48

Jawaban oleh Dave S dan gbjbaanb yang benar . (Dan pernyataan Luc Danton juga benar, meskipun ini lebih merupakan efek samping dari pelarangan string KK daripada aturan asli yang melarangnya.)

Tetapi untuk menjernihkan beberapa kebingungan, saya akan menambahkan beberapa eksposisi lebih lanjut. Berbagai komentar tertaut ke komentar saya di bugzilla GCC yang memberikan contoh berikut:

std::string s("str");
const char* p = s.data();
{
    std::string s2(s);
    (void) s[0];
}
std::cout << *p << '\n';  // p is dangling

Inti dari contoh itu adalah untuk mendemonstrasikan mengapa string referensi GCC dihitung (COW) tidak valid di C ++ 11. Standar C ++ 11 membutuhkan kode ini untuk bekerja dengan benar. Tidak ada dalam kode yang mengizinkan puntuk menjadi tidak valid di C ++ 11.

Menggunakan std::stringimplementasi lama dengan referensi terhitung GCC , kode tersebut memiliki perilaku yang tidak ditentukan, karena p tidak valid, menjadi penunjuk yang menggantung. (Apa yang terjadi adalah ketika s2dikonstruksi, ia membagikan datanya s, tetapi mendapatkan referensi non-const melalui s[0]mengharuskan datanya tidak dibagikan, begitu sjuga "salinan saat menulis" karena referensi s[0]tersebut berpotensi dapat digunakan untuk menulis s, lalu s2pergi keluar dari ruang lingkup, menghancurkan array yang ditunjukkan oleh p).

Standar C ++ 03 secara eksplisit mengizinkan perilaku tersebut di 21.3 [lib.basic.string] p5 di mana dikatakan bahwa setelah panggilan ke data()panggilan pertama operator[]()dapat membatalkan pointer, referensi, dan iterator. Jadi string COW GCC adalah implementasi C ++ 03 yang valid.

Standar C ++ 11 tidak lagi mengizinkan perilaku itu, karena tidak ada panggilan ke yang operator[]()dapat membatalkan pointer, referensi atau iterator, terlepas dari apakah mereka mengikuti panggilan ke data().

Jadi contoh di atas harus berfungsi di C ++ 11, tetapi tidak berfungsi dengan string COW jenis libstdc ++, oleh karena itu jenis string COW tersebut tidak diizinkan di C ++ 11.

Jonathan Wakely
sumber
3
Implementasi yang tidak dibagikan pada panggilan ke .data()(dan setiap pengembalian pointer, referensi, atau iterator) tidak mengalami masalah tersebut. Yaitu (invariant) buffer kapan saja tidak dibagikan, atau dibagikan tanpa referensi eksternal. Saya pikir Anda bermaksud komentar tentang contoh ini sebagai laporan bug informal-sebagai-komentar, maaf karena kesalahpahaman! Tetapi seperti yang Anda lihat dengan mempertimbangkan implementasi seperti yang saya jelaskan di sini, yang berfungsi dengan baik di C ++ 11 ketika noexceptpersyaratan diabaikan, contoh tidak mengatakan apapun tentang formal. Saya dapat memberikan kode jika Anda mau.
Cheers and hth. - Alf
7
Jika Anda membatalkan berbagi di hampir setiap akses ke string maka Anda kehilangan semua manfaat berbagi. Implementasi COW harus praktis agar pustaka standar repot menggunakannya karena std::string, dan saya benar-benar ragu Anda dapat mendemonstrasikan string COW yang berguna dan berkinerja yang memenuhi persyaratan pembatalan C ++ 11. Jadi saya berpendapat bahwa noexceptspesifikasi yang ditambahkan pada menit terakhir adalah konsekuensi dari pelarangan string KK, bukan alasan yang mendasarinya. N2668 tampak sangat jelas, mengapa Anda terus menyangkal bukti jelas dari maksud panitia yang diuraikan di sana?
Jonathan Wakely
Juga, ingat itu data()adalah fungsi anggota const, jadi harus aman untuk memanggil secara bersamaan dengan anggota const lainnya, dan misalnya untuk memanggil data()secara bersamaan dengan utas lain yang membuat salinan string. Jadi, Anda akan memerlukan semua overhead mutex untuk setiap operasi string, bahkan yang const, atau kompleksitas struktur yang dihitung referensi yang dapat berubah tanpa kunci, dan setelah semua itu Anda hanya mendapatkan berbagi jika Anda tidak pernah memodifikasi atau mengakses string Anda, begitu banyak, banyak string akan memiliki jumlah referensi satu. Harap berikan kode, jangan ragu untuk mengabaikan noexceptjaminan.
Jonathan Wakely
2
Baru saja menyusun beberapa kode sekarang saya menemukan bahwa ada 129 basic_stringfungsi anggota, ditambah fungsi gratis. Biaya abstraksi: kode versi ke nol baru yang tidak dioptimalkan ini 50 hingga 100% lebih lambat dengan g ++ dan MSVC. Itu tidak melakukan keamanan utas (cukup mudah memanfaatkan shared_ptr, menurut saya) dan itu hanya cukup untuk mendukung pengurutan kamus untuk tujuan waktu, tetapi bug modulo itu membuktikan titik bahwa referensi yang dihitung basic_stringdiizinkan, kecuali untuk noexceptpersyaratan C ++ . github.com/alfps/In-principle-demo-of-ref-counted-basic_string
Bersulang dan hth. - Alf
1
Mari kita lanjutkan diskusi ini dalam obrolan .
Jonathan Wakely
20

Memang, Kontrak Karya adalah mekanisme yang dapat diterima untuk membuat string lebih cepat ... tapi ...

itu membuat kode multithreading lebih lambat (semua penguncian itu untuk memeriksa apakah Anda satu-satunya yang menulis membunuh kinerja saat menggunakan banyak string). Inilah alasan utama kematian kontrak beberapa tahun yang lalu.

Alasan lainnya adalah []operator akan mengembalikan data string kepada Anda, tanpa perlindungan apa pun bagi Anda untuk menimpa string yang diharapkan orang lain tidak berubah. Hal yang sama berlaku untuk c_str()dan data().

Quick google mengatakan bahwa multithreading pada dasarnya adalah alasan mengapa secara efektif tidak diizinkan (tidak secara eksplisit).

Proposal mengatakan:

Usul

Kami mengusulkan agar semua operasi iterator dan akses elemen dengan aman dapat dieksekusi secara bersamaan.

Kami meningkatkan stabilitas operasi bahkan dalam kode sekuensial.

Perubahan ini secara efektif melarang penerapan salin-saat-tulis.

diikuti oleh

Potensi kerugian terbesar dalam performa karena peralihan dari implementasi salin-saat-tulis adalah peningkatan konsumsi memori untuk aplikasi dengan string sebagian besar baca yang sangat besar. Namun, kami percaya bahwa untuk aplikasi tersebut, tali adalah solusi teknis yang lebih baik, dan merekomendasikan proposal tali untuk dipertimbangkan untuk dimasukkan dalam Perpustakaan TR2.

Tali adalah bagian dari STLPort dan SGI STL.

gbjbaanb.dll
sumber
2
Masalah operator [] sebenarnya bukan masalah. Varian const memang menawarkan perlindungan, dan varian non-const selalu memiliki opsi untuk melakukan Kontrak Karya pada saat itu (atau benar-benar gila dan menyiapkan kesalahan halaman untuk memicunya).
Christopher Smith
+1 Pergi ke masalah.
Cheers and hth. - Alf
5
hanya konyol bahwa kelas std :: cow_string tidak disertakan, dengan lock_buffer (), dll. Ada banyak kali saya tahu threading tidak menjadi masalah. sebenarnya lebih sering daripada tidak.
Erik Aronesty
Saya suka saran alternatif, tali ig. Saya ingin tahu apakah ada jenis dan implementasi alternatif lain yang tersedia.
Voltaire
5

Dari 21.4.2 konstruktor basic_string dan operator penugasan [string.cons]

basic_string(const basic_string<charT,traits,Allocator>& str);

[...]

2 Efek : Membangun objek kelas basic_stringseperti yang ditunjukkan pada Tabel 64. [...]

Tabel 64 sangat membantu mendokumentasikan bahwa setelah konstruksi objek melalui konstruktor (copy) ini, this->data()memiliki nilai:

menunjuk ke elemen pertama dari salinan yang dialokasikan dari array yang elemen pertamanya ditunjukkan oleh str.data ()

Ada persyaratan serupa untuk konstruktor serupa lainnya.

Luc Danton
sumber
+1 Menjelaskan bagaimana C ++ 11 (setidaknya sebagian) melarang KK.
Cheers and hth. - Alf
Maaf, saya lelah. Itu tidak menjelaskan lebih dari itu panggilan .data () harus memicu penyalinan COW jika buffer saat ini dibagikan. Masih itu info yang berguna jadi saya membiarkan upvote berdiri.
Cheers and hth. - Alf
1

Karena sekarang dijamin bahwa string disimpan secara berdekatan dan Anda sekarang diizinkan untuk mengambil pointer ke penyimpanan internal string, (yaitu & str [0] berfungsi seperti yang akan dilakukan untuk array), tidak mungkin membuat COW yang berguna penerapan. Anda harus membuat salinan untuk terlalu banyak hal. Bahkan hanya menggunakan operator[]atau begin()pada string non-const akan membutuhkan salinan.

Dirk Holsopple
sumber
1
Saya pikir string di C ++ 11 dijamin akan disimpan berdekatan.
mfontanini
4
Di masa lalu Anda harus membuat salinan dalam semua situasi itu dan itu tidak menjadi masalah ...
David Rodríguez - dribeas
@mfontanini ya, tapi sebelumnya tidak
Dirk Holsopple
3
Meskipun C ++ 11 menjamin string bersebelahan, itu ortogonal untuk melarang string COW. String COW GCC bersebelahan, jadi jelaslah klaim Anda bahwa "tidak mungkin membuat implementasi COW yang berguna" adalah palsu.
Jonathan Wakely
1
@supercat, meminta penyimpanan cadangan (misalnya dengan memanggil c_str()) harus O (1) dan tidak boleh melempar, dan tidak boleh memasukkan data race, jadi sangat sulit untuk memenuhi persyaratan tersebut jika Anda malas menggabungkan. Dalam praktiknya, satu-satunya pilihan yang masuk akal adalah selalu menyimpan data yang berdekatan.
Jonathan Wakely
1

Apakah COW basic_stringdilarang di C ++ 11 dan yang lebih baru?

Mengenai

Apakah saya benar bahwa C ++ 11 tidak menerima implementasi berbasis COW std::string?

Iya.

Mengenai

Jika demikian, apakah pembatasan ini secara eksplisit dinyatakan di suatu tempat dalam standar baru (di mana)?

Hampir secara langsung, dengan persyaratan kompleksitas konstan untuk sejumlah operasi yang memerlukan O ( n ) penyalinan fisik dari data string dalam implementasi KK.

Misalnya untuk fungsi anggota

auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;

… Yang dalam implementasi COW akan - keduanya memicu penyalinan data string untuk membatalkan pembagian nilai string, standar C ++ 11 memerlukan

C ++ 11 §21.4.5 / 4 :

Kompleksitas: konstanta waktu.

… Yang mengesampingkan penyalinan data tersebut, dan karenanya, KK.

C ++ 03 didukung implementasi SAPI oleh tidak memiliki persyaratan kompleksitas konstan ini, dan oleh, di bawah kondisi pembatasan tertentu, yang memungkinkan panggilan ke operator[](), at(), begin(), rbegin(), end(), atau rend()untuk referensi invalidate, pointer dan iterator mengacu pada item tali, yaitu untuk kemungkinan dikenakan Penyalinan data KK. Dukungan ini telah dihapus di C ++ 11.


Apakah COW juga dilarang melalui aturan pembatalan C ++ 11?

Dalam jawaban lain yang pada saat penulisan dipilih sebagai solusi, dan yang sangat disukai dan oleh karena itu dipercaya, ditegaskan bahwa

Untuk string COW, memanggil non- const operator[]akan memerlukan pembuatan salinan (dan referensi yang tidak valid), yang tidak diizinkan oleh [kutipan] paragraf di atas [C ++ 11 §21.4.1 / 6]. Oleh karena itu, tidak lagi legal untuk memiliki string COW di C ++ 11.

Pernyataan tersebut tidak benar dan menyesatkan dalam dua hal utama:

  • Ini salah menunjukkan bahwa hanya pengakses non- constitem yang perlu memicu penyalinan data COW.
    Tetapi pengakses constitem juga perlu memicu penyalinan data, karena mereka mengizinkan kode klien untuk membentuk referensi atau petunjuk yang (dalam C ++ 11) tidak diizinkan untuk membatalkannya nanti melalui operasi yang dapat memicu penyalinan data COW.
  • Ini salah mengasumsikan bahwa penyalinan data KK dapat menyebabkan pembatalan referensi.
    Tetapi dalam implementasi yang benar, penyalinan data COW, pembatalan pembagian nilai string, dilakukan pada titik sebelum ada referensi yang dapat dibatalkan.

Untuk melihat bagaimana implementasi C ++ 11 COW yang benar basic_stringakan bekerja, ketika persyaratan O (1) yang membuat ini tidak valid diabaikan, pikirkan implementasi di mana string dapat beralih di antara kebijakan kepemilikan. Instance string dimulai dengan kebijakan Sharable. Dengan kebijakan ini aktif, tidak ada referensi item eksternal. Instance dapat bertransisi ke kebijakan Unik, dan harus melakukannya ketika referensi item berpotensi dibuat seperti dengan panggilan ke .c_str()(setidaknya jika itu menghasilkan pointer ke buffer internal). Dalam kasus umum beberapa contoh berbagi kepemilikan nilai, ini memerlukan penyalinan data string. Setelah transisi ke kebijakan Unik, instance hanya dapat beralih kembali ke Sharable melalui operasi yang membatalkan semua referensi, seperti penetapan.

Jadi, walaupun kesimpulan jawaban itu, bahwa string KK dikesampingkan, benar, alasan yang ditawarkan salah dan sangat menyesatkan.

Saya menduga penyebab kesalahpahaman ini adalah catatan non-normatif dalam lampiran C C ++ 11:

C ++ 11 §C.2.11 [diff.cpp03.strings], tentang §21.3:

Ubah : basic_stringpersyaratan tidak lagi mengizinkan string yang dihitung referensi
Rasional: Invalidasi sedikit berbeda dengan string yang dihitung referensi. Perubahan ini mengatur perilaku (sic) untuk Standar Internasional ini.
Efek pada fitur asli: Kode C ++ 2003 yang valid dapat dijalankan secara berbeda dalam Standar Internasional ini

Di sini alasan menjelaskan alasan utama mengapa seseorang memutuskan untuk menghapus dukungan COW khusus C ++ 03. Alasan ini, mengapa , bukanlah bagaimana standar secara efektif melarang penerapan KK. Standar melarang sapi melalui persyaratan O (1).

Singkatnya, aturan pembatalan C ++ 11 tidak mengesampingkan implementasi COW std::basic_string. Tetapi mereka mengesampingkan implementasi COW tak terbatas gaya C ++ 03 yang cukup efisien seperti yang ada di setidaknya salah satu implementasi pustaka standar g ++. Dukungan khusus C ++ 03 COW memungkinkan efisiensi praktis, khususnya menggunakan constpengakses item, dengan mengorbankan aturan yang halus dan rumit untuk pembatalan:

C ++ 03 §21.3 / 5 yang mencakup dukungan COW "panggilan pertama":

Referensi, pointer, dan iterators mengacu pada unsur-unsur dari basic_stringurutan mungkin tidak berlaku karena penggunaan berikut yang basic_stringobjek:
- Sebagai argumen untuk fungsi non-anggota swap()(21.3.7.8), operator>>()(21.3.7.9), dan getline()(21.3. 7.9).
- Sebagai argumen untuk basic_string::swap().
- Memanggil data()dan c_str()fungsi anggota.
- Memanggil non constfungsi anggota, kecuali operator[](), at(), begin(), rbegin(), end(), dan rend().
- Setelah ke salah satu penggunaan di atas kecuali bentuk insert()dan erase()yang iterator kembali, panggilan pertama untuk non constfungsi anggota operator[](), at(), begin(), rbegin(),end(), atau rend().

Aturan-aturan ini sangat rumit dan halus sehingga saya ragu banyak programmer, jika ada, dapat memberikan ringkasan yang tepat. Saya tidak bisa.


Bagaimana jika persyaratan O (1) diabaikan?

Jika persyaratan waktu konstan C ++ 11 pada mis operator[]diabaikan, maka COW untuk basic_stringdapat secara teknis layak, tetapi sulit untuk diterapkan.

Operasi yang dapat mengakses konten string tanpa melakukan penyalinan data COW meliputi:

  • Penggabungan melalui +.
  • Output melalui <<.
  • Menggunakan basic_stringsebagai argumen untuk fungsi pustaka standar.

Yang terakhir karena pustaka standar diizinkan untuk mengandalkan implementasi pengetahuan dan konstruksi tertentu.

Selain itu, implementasi dapat menawarkan berbagai fungsi non-standar untuk mengakses konten string tanpa memicu penyalinan data COW.

Faktor utama yang menyulitkan adalah bahwa dalam C ++ 11 basic_stringakses item harus memicu penyalinan data (membatalkan pembagian data string) tetapi diperlukan untuk tidak melempar , misalnya C ++ 11 §21.4.5 / 3 “ Throws: Nothing.”. Sehingga tidak dapat menggunakan alokasi dinamis biasa untuk membuat buffer baru untuk penyalinan data COW. Salah satu cara untuk mengatasinya adalah dengan menggunakan heap khusus di mana memori dapat dicadangkan tanpa benar-benar dialokasikan, dan kemudian mencadangkan jumlah yang diperlukan untuk setiap referensi logis ke nilai string. Mencadangkan dan membatalkan reservasi di heap seperti itu dapat menjadi waktu yang konstan, O (1), dan mengalokasikan jumlah yang telah dipesan, dapatnoexcept. Untuk memenuhi persyaratan standar, dengan pendekatan ini tampaknya perlu ada satu heap berbasis reservasi khusus per pengalokasi yang berbeda.


Catatan:
¹ Pengakses constitem memicu penyalinan data KK karena memungkinkan kode klien untuk mendapatkan referensi atau penunjuk ke data, yang tidak diizinkan untuk dibatalkan oleh penyalinan data selanjutnya yang dipicu oleh misalnya pengakses non- constitem.

Cheers and hth. - Alf
sumber
3
" Contoh Anda adalah contoh bagus dari implementasi C ++ 11 yang salah. Mungkin itu benar untuk C ++ 03." Ya itu inti dari contohnya . Ini menunjukkan string COW yang legal di C ++ 03 karena tidak melanggar aturan pembatalan iterator lama dan tidak legal di C ++ 11 karena melanggar aturan pembatalan iterator baru. Dan itu juga bertentangan dengan pernyataan yang saya kutip di komentar di atas.
Jonathan Wakely
2
Jika Anda ingin mengatakan sharable tidak awalnya bersama saya tidak akan berpendapat. Mengatakan sesuatu pada awalnya dibagikan hanya membingungkan. Dibagikan dengan dirinya sendiri? Bukan itu arti kata itu. Tapi saya ulangi: upaya Anda untuk berpendapat bahwa aturan pembatalan iterator C ++ 11 tidak melarang beberapa string COW hipotetis yang tidak pernah digunakan dalam praktik (dan akan memiliki kinerja yang tidak dapat diterima), ketika mereka pasti melarang jenis string COW yang digunakan dalam praktik, agak bersifat akademis dan tidak berguna.
Jonathan Wakely
5
String COW yang Anda usulkan menarik, tapi saya tidak yakin seberapa berguna string itu. Inti dari string COW adalah untuk hanya menyalin data string jika kedua string tersebut ditulis. Penerapan yang Anda sarankan memerlukan penyalinan saat terjadi operasi baca yang ditentukan pengguna. Bahkan jika kompilator mengetahui bahwa ini hanya sebuah bacaan, ia tetap harus menyalin. Selanjutnya, menyalin string Unik akan menghasilkan salinan data stringnya (mungkin ke status yang Dapat Dibagikan), yang lagi-lagi membuat COW agak tidak berguna. Jadi tanpa jaminan kerumitan, Anda bisa menulis ... string COW yang sangat jelek .
Nicol Bolas
2
Jadi, meskipun Anda secara teknis benar bahwa jaminan kompleksitaslah yang mencegah Anda menulis bentuk KK apa pun , sebenarnya [basic.string] / 5lah yang mencegah Anda untuk menulis bentuk string KK yang benar-benar berguna .
Nicol Bolas
4
@JonathanWakely: (1) Kutipan Anda bukanlah pertanyaannya. Inilah pertanyaannya: “Apakah saya benar bahwa C ++ 11 tidak menerima implementasi berbasis COW dari std :: string? Jika demikian, apakah batasan ini secara eksplisit dinyatakan di suatu tempat dalam standar baru (di mana)? ” (2) Pendapat Anda bahwa KK std::string, jika mengabaikan persyaratan O (1), akan menjadi tidak efisien, adalah pendapat Anda. Saya tidak tahu seperti apa performanya, tetapi saya pikir pernyataan itu lebih dikedepankan untuk merasakannya, untuk getaran yang disampaikannya, daripada relevansinya dengan jawaban ini.
Cheers and hth. - Alf
0

Saya selalu bertanya-tanya tentang sapi yang tidak berubah: sekali sapi dibuat, saya hanya dapat diubah melalui penugasan dari sapi lain, sehingga akan sesuai dengan standar.

Saya punya waktu untuk mencobanya hari ini untuk tes perbandingan sederhana: peta berukuran N yang dikunci oleh string / sapi dengan setiap node memegang satu set semua string di peta (kami memiliki jumlah objek NxN).

Dengan string berukuran ~ 300 byte dan N = 2000 sapi sedikit lebih cepat dan menggunakan hampir urutan besarnya lebih sedikit memori. Lihat di bawah, ukuran dalam kbs, run b dengan sapi.

~/icow$ ./tst 2000
preparation a
run
done a: time-delta=6 mem-delta=1563276
preparation b
run
done a: time-delta=3 mem-delta=186384
zzz777
sumber