'lakukan ... saat' vs. 'saat'


86

Kemungkinan Duplikat:
While vs. Do While
Kapan saya harus menggunakan do-while daripada while loop?

Saya telah memprogram untuk sementara waktu sekarang (2 tahun bekerja + 4,5 tahun gelar + 1 tahun pra-perguruan tinggi), dan saya tidak pernah menggunakan do-while loop pendek karena dipaksa dalam kursus Pengenalan Pemrograman. Saya memiliki perasaan yang berkembang bahwa saya melakukan pemrograman yang salah jika saya tidak pernah mengalami sesuatu yang begitu mendasar.

Mungkinkah saya tidak mengalami keadaan yang benar?

Apa sajakah contoh di mana perlu menggunakan do-while daripada while?

(Sekolah saya hampir semuanya dalam C / C ++ dan pekerjaan saya dalam C #, jadi jika ada bahasa lain yang benar-benar masuk akal karena do-whiles bekerja secara berbeda, maka pertanyaan-pertanyaan ini tidak benar-benar berlaku.)

Untuk memperjelas ... Saya tahu perbedaan antara a whiledan a do-while. Saat memeriksa kondisi keluar dan kemudian melakukan tugas. do-whilemelakukan tugas dan kemudian memeriksa kondisi keluar.


43
Untuk apa nilainya, setelah satu dekade pemrograman sebagai karier saya, saya telah menggunakan loop do-while seperti sekali atau dua kali.
Matt Greer

@Matt - Itu membuatku merasa lebih baik. Setidaknya itu berarti saya tidak sendiri.
mphair

2
Saya akan mendukung Matt dan menambahkan satu dekade lagi atau lebih untuk itu. Saya juga jarang menggunakan loop do-while.
Quentin-starin

BANYAK duplikat. Ini salah satu yang tertaut ke banyak dari mereka: stackoverflow.com/questions/3094972/…
gnovice

3
"Pertanyaan utama" yang benar tampaknya adalah stackoverflow.com/questions/224059/…
Donal Fellows

Jawaban:


116

Jika Anda selalu ingin loop dijalankan setidaknya sekali. Itu tidak umum, tetapi saya menggunakannya dari waktu ke waktu. Satu kasus di mana Anda mungkin ingin menggunakannya adalah mencoba mengakses sumber daya yang mungkin memerlukan percobaan ulang, mis

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);

3
Jadi saya kira ini akan mengikuti di bawah "Saya belum mengalami keadaan itu."
mphair

7
sejujurnya, saya sangat jarang mengalami situasi ketika saya hanya perlu menggunakan do..selain itu ..
Stan R.

1
Mungkin agak pendek, tapi Bob benar. Do / while harus digunakan ketika Anda ingin menjalankan blok kode setidaknya satu kali . Anda harus menggunakan while loop ketika Anda tidak tahu apakah Anda ingin menjalankannya sekali saja. Karena itu, saya dapat memberi tahu Anda bahwa dengan sekitar 15 tahun pengalaman pengembangan, saya telah menggunakan lebih banyak while loop daripada do / while loop.
ConsultUtah

1
Saya telah menggunakannya dari waktu ke waktu juga, meskipun jarang. Setelah beberapa saat, biasanya mereka akan direfraktorisasi menjadi while loop juga - hanya karena area di sekitarnya berubah dan melakukan ... sementara lebih kikuk daripada sebelumnya.
Joshua

2
Ini cukup umum. Tetapi saya tidak mengerti mengapa dalam contoh Anda, Anda tidak akan menggunakan loop sementara. Dan saya tidak mengerti mengapa jawaban ini diberi suara positif.

65

do-while lebih baik jika kompilator tidak kompeten dalam pengoptimalan. do-while hanya memiliki satu lompatan bersyarat, berbeda dengan for dan while yang memiliki lompatan bersyarat dan lompatan tanpa syarat. Untuk CPU yang menggunakan pipeline dan tidak melakukan prediksi cabang, hal ini dapat membuat perbedaan besar dalam performa pengulangan yang ketat.

Selain itu, karena sebagian besar kompiler cukup pintar untuk melakukan pengoptimalan ini, semua loop yang ditemukan dalam kode yang didekompilasi biasanya akan bersifat do-while (bahkan jika decompiler repot-repot merekonstruksi loop dari gotos lokal mundur sama sekali).


5
1 untuk menambahkan informasi teknis yang relevan dengan pilihan antara bentuk lingkaran.
Quentin-starin

2
Tidak hanya prematur tapi juga tidak berguna. Jika Anda benar-benar menginginkan loop sementara yaitu kemampuan untuk mengulang 0 kali, Anda harus menyertakan loop dalam if yang membawa lompatan itu kembali.
JeremyP

3
@ Jeremy: Lompatan yang Anda bicarakan berada di luar loop, tidak dieksekusi sebanyak N kali.
Ben Voigt

1
Pertimbangkan juga penggunaan klasik do-while di perangkat Duff (di mana loop sementara diubah menjadi do-while yang tidak digulung dengan langkah yang lebih besar ditambah tabel lompat untuk menangani sisanya) yang secara dramatis mengurangi overhead loop - dalam aplikasi seperti memset, memcmp, memcpy itu dapat meningkatkan throughput dengan faktor 10.
Ben Voigt

@BenVoigt Saya tahu komentar Anda sudah berumur satu dekade sekarang, tetapi Perangkat Duff tidak boleh disebutkan tanpa peringatan yang sangat penting - ini menjadi kurang efisien pada kompiler modern, karena kompiler modern biasanya dapat dengan cerdas membuka gulungan langsung sendiri sebagai optimal untuk mesin target , sementara mereka umumnya tidak memiliki logika untuk mengetahui maksud dari Perangkat Duff dan karenanya tidak dapat mengoptimalkannya juga. Yang merupakan pelajaran bagus tentang mengoptimalkan kode untuk beberapa mesin target alih-alih untuk "pengoptimal yang cukup canggih" abstrak.
mtraceur

12

Saya telah menggunakan ini dalam fungsi TryDeleteDirectory. Sesuatu seperti ini

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);

Bagus. Ini adalah contoh pertama yang benar-benar masuk akal untuk digabungkan dalam do ... while.
Joshua

4
Mengapa / bagaimana ini lebih baik daripada standar while?
Josh Stodola

Perulangan akan selalu dijalankan satu kali, jadi Anda mungkin ingin melakukan sesuatu, lalu coba lagi jika gagal. Jika Anda menggunakan while loop, Anda akan memeriksa apakah itu gagal bahkan sebelum Anda melakukannya pada iterasi pertama.
NibblyPig

1
@SLC Tapi tidakkah Anda ingin memeriksa apakah direktori sudah ada sebelumnya?
Josh Stodola

1
@Josh Dalam contoh ini, ya. Tetapi jika Anda mencoba membuka koneksi ke server yang sibuk, Anda akan terhubung terlebih dahulu, dan melihat apakah responsnya 'sibuk'. Jika ya, Anda akan mencoba lagi beberapa kali sebelum menyerah.
NibblyPig

11

Do while berguna ketika Anda ingin menjalankan sesuatu setidaknya sekali. Adapun contoh yang baik untuk menggunakan do while vs. while, katakanlah Anda ingin membuat yang berikut ini: Kalkulator.

Anda dapat melakukan pendekatan ini dengan menggunakan loop dan memeriksa setelah setiap perhitungan jika orang tersebut ingin keluar dari program. Sekarang Anda mungkin dapat berasumsi bahwa setelah program dibuka orang tersebut ingin melakukan ini setidaknya sekali sehingga Anda dapat melakukan hal berikut:

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue

2
Sebenarnya, setelah Anda menyebutkannya, semua jenis antarmuka berbasis menu konsol akan bekerja dengan baik dalam do ... while loop juga. Misalnya, meminta opsi (satu tombol pada satu waktu) dan hanya keluar saat mereka memilih lanjutkan atau keluar.
Joshua

7
continueadalah kata kunci; D
Thomas Eding

Atrinithis: Lol ... Saya terpeleset. Terima kasih telah mengoreksi saya di sana.

== truetidak dibutuhkan. cont == truejika cont benar mengembalikan true. Itu sama sekali tidak berguna.
Tn. DeleteMyMessages

11

Ini semacam jawaban tidak langsung, tetapi pertanyaan ini membuat saya memikirkan logika di baliknya, dan saya pikir ini mungkin layak untuk dibagikan.

Seperti yang dikatakan orang lain, Anda menggunakan do ... whileloop ketika Anda ingin mengeksekusi body setidaknya sekali. Tetapi dalam keadaan apa Anda ingin melakukan itu?

Nah, kelas situasi yang paling jelas yang dapat saya pikirkan adalah ketika nilai awal ("tidak dipersiapkan") dari kondisi pemeriksaan sama dengan saat Anda ingin keluar . Ini berarti Anda perlu mengeksekusi badan pengulangan satu kali untuk membuat kondisi prima ke nilai yang tidak keluar, lalu melakukan pengulangan sebenarnya berdasarkan kondisi tersebut. Apa dengan programmer yang begitu malas, seseorang memutuskan untuk membungkusnya dalam struktur kontrol.

Jadi misalnya, membaca karakter dari port serial dengan batas waktu mungkin menggunakan format (dengan Python):

response_buffer = []
char_read = port.read(1)

while char_read:
    response_buffer.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

response = ''.join(response_buffer)

Perhatikan duplikasi kode: char_read = port.read(1) . Jika Python memiliki do ... whileloop, saya mungkin telah menggunakan:

do:
    char_read = port.read(1)
    response_buffer.append(char_read)
while char_read

Manfaat tambahan untuk bahasa yang membuat lingkup baru untuk loop: char_readtidak mencemari namespace fungsi. Tetapi perhatikan juga bahwa ada cara yang lebih baik untuk melakukan ini, dan itu adalah dengan menggunakan Nonenilai Python :

response_buffer = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response_buffer.append(char_read)

response = ''.join(response_buffer)

Jadi, inilah inti dari poin saya: dalam bahasa dengan jenis nullable, situasi initial_value == exit_valuemuncul jauh lebih sering, dan yang mungkin mengapa Anda tidak mengalami hal itu. Saya tidak mengatakan itu tidak pernah terjadi, karena masih ada waktu dimana suatu fungsi akan kembaliNone untuk menandakan kondisi yang valid. Tetapi menurut pendapat saya yang terburu-buru dan dipertimbangkan secara singkat, ini akan terjadi lebih banyak jika bahasa yang Anda gunakan tidak memungkinkan untuk nilai yang menandakan: variabel ini belum diinisialisasi.

Ini bukan alasan yang sempurna: pada kenyataannya, sekarang nilai null sudah umum, mereka hanya membentuk satu elemen lagi dari kumpulan nilai valid yang dapat diambil variabel. Tetapi secara praktis, programmer memiliki cara untuk membedakan antara variabel yang berada dalam status sensible, yang mungkin termasuk status keluar loop, dan berada dalam status tidak diinisialisasi.


Ini adalah salah satu tanggapan menarik yang pernah saya baca di sini. Kontribusi yang bagus.
Bob Moore

Kedua versi itu tidak setara. Jika pembacaan pertama kembali None, whileversi dengan benar tidak menambahkan apa pun ke buffer respons, tetapi doversi Anda selalu menambahkan sesuatu.
David Stone

@VidNike read()seharusnya tidak pernah kembali None. Jika Anda menggunakan perpustakaan di mana ia melakukannya, premis tidak berlaku (yaitu, nilai sentinel tidak ada dalam kumpulan nilai pemeriksaan yang mungkin).
detly

Dengan hasil edit terakhir Anda, saya melihat apa yang seharusnya saya katakan adalah ''sebagai ganti None. Semacam nilai yang dinilai salah. Kapur hingga ketidaktahuan saya dengan readfungsi Python .
David Stone

@DavidStone Saya tidak mengerti. Jika read()dikembalikan '', tidak ada yang akan ditambahkan ke string, itu kosong.
detly

7

Saya menggunakannya sedikit ketika saya masih di sekolah, tetapi tidak begitu banyak sejak itu.

Secara teori, mereka berguna ketika Anda ingin badan perulangan dijalankan satu kali sebelum pemeriksaan kondisi keluar. Masalahnya adalah bahwa untuk beberapa contoh di mana saya tidak menginginkan pemeriksaan terlebih dahulu, biasanya saya ingin pemeriksaan keluar di tengah badan perulangan daripada di bagian paling akhir. Dalam hal ini, saya lebih suka menggunakan yang terkenal for (;;)dengan suatu if (condition) exit;tempat di tubuh.

Faktanya, jika saya agak goyah pada kondisi loop keluar, terkadang saya merasa berguna untuk mulai menulis loop sebagai for (;;) {}pernyataan keluar jika diperlukan, dan kemudian setelah selesai saya dapat melihat apakah itu bisa " dibersihkan "dengan memindahkan initilisasi, kondisi keluar, dan / atau kode kenaikan di dalam fortanda kurung.


5
Karena penasaran ... mengapa "untuk (;;)" bukannya "sementara (benar)"?
mphair

4
Mungkin hanya rasa. Saya telah tumbuh untuk menyamakan for(;;)dengan "putaran tak terbatas", sedangkan while(true)saya harus berhenti dan berpikir tentang. Mungkin karena saya mengkode C sebelum ada file true. Dulu kami hanya memiliki TRUEmakro, dan jika ada masalah, saya harus meyakinkan diri sendiri bahwa makro belum didefinisikan ulang untuk 0entah bagaimana (itu terjadi!). Dengan for(;;)tidak ada kemungkinan itu. Jika Anda bersikeras pada formulir sementara, saya hampir lebih suka melihat while (1). Tentu saja kemudian beberapa orang mungkin bertanya-tanya apakah itu bukan surat yang saya ...
TED

1
@mphair: Ya, jika Anda mencatat teks yang dimasukkan editor saat Anda mencetak miring atau codeifyteks, Anda dapat langsung mengetiknya sendiri di kolom komentar. Saya telah melihat beberapa orang memasukkan hyperlink, tetapi itu agak terlalu hardcore bagi saya.
TED

2
@TED: Notasi pilihan saya untuk loop-sampai-eksplisit-keluar adalah "lakukan {} sementara (1);". Kebetulan, dalam sistem tertanam bekerja, paradigma loop normal saya adalah "i = 10; do {} while (- i);". Untuk loop ketat, itu jauh lebih cepat daripada biasanya untuk (); Saya pikir itu lebih mudah dibaca untuk menggunakannya secara konsisten sebagai pola loop ketika up-count tidak diperlukan daripada digunakan secara sewenang-wenang untuk () dalam kasus-kasus non-performance-critical.
supercat

2
Menambahkan ke while (1) dan untuk (;;) disusi, saya telah melihat kode menggunakan for (EVER) dengan EVER didefinisikan sebagai ;;
asr

6

Situasi di mana Anda selalu perlu menjalankan sepotong kode sekali, dan bergantung pada hasilnya, mungkin lebih banyak. Hal yang sama dapat diproduksi dengan whileloop biasa juga.

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);

6

do whileadalah jika Anda ingin menjalankan blok kode setidaknya sekali. whiledi sisi lain tidak selalu berjalan tergantung pada kriteria yang ditentukan.


5

Sesederhana itu:

precondition vs postcondition

  • sementara (cond) {...} - prasyarat, itu mengeksekusi kode hanya setelah pemeriksaan.
  • do {...} while (cond) - postcondition, kode dieksekusi setidaknya sekali.

Sekarang Anda tahu rahasianya .. gunakan dengan bijak :)


1
Seperti saya katakan, saya tahu cara kerjanya, saya hanya tidak yakin dalam hal apa yang satu masuk akal dibandingkan yang lain.
mphair

Adalah logis bahwa Anda menggunakan do {} saat Anda tahu pasti bahwa Anda harus meneruskan setidaknya sekali melalui perulangan. Seperti misalnya jika Anda memiliki fungsi yang menemukan elemen dalam array dan sebelumnya Anda telah meletakkan if array.IsEmpty () lalu return; . Jika lolos pemeriksaan itu, Anda bisa dengan aman menggunakan do {} while. do-while juga mudah untuk dipikirkan, sebagai loop berulang: "Saya makan sampai saya puas" diterjemahkan menjadi do {eat ();} while (! puas ();). Menguji kondisi sebelum loop dianggap lebih aman .. dan itulah mengapa digunakan lebih sering.
Ioan Paul Pirau

4

Saya melihat bahwa pertanyaan ini telah dijawab dengan memadai, tetapi saya ingin menambahkan skenario kasus penggunaan yang sangat spesifik ini. Anda dapat mulai menggunakan do ... sementara lebih sering.

do
{
   ...
} while (0)

sering digunakan untuk multi-baris #defines. Sebagai contoh:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * h

Ini berfungsi dengan baik untuk:

r = 4;
h = 3;
compute_values;

-tapi- ada gotcha untuk:

if (shape == circle)  compute_values;

karena ini berkembang menjadi:

if (shape == circle) area = pi *r * r;
volume = area * h;

Jika Anda membungkusnya dalam do ... while (0) loop itu dengan benar meluas menjadi satu blok:

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);

2

Jawabannya sejauh ini merangkum penggunaan umum do-while. Tapi OP meminta contoh, jadi ini satu: Dapatkan masukan pengguna. Tetapi masukan pengguna mungkin tidak valid - jadi Anda meminta masukan, memvalidasinya, melanjutkan jika valid, jika tidak, ulangi.

Dengan do-while, Anda mendapatkan input sedangkan input tidak valid. Dengan while-loop biasa, Anda mendapatkan input sekali, tetapi jika tidak valid, Anda mendapatkannya lagi dan lagi hingga valid. Tidak sulit untuk melihat bahwa yang pertama lebih pendek, lebih elegan, dan lebih sederhana untuk dipelihara jika badan loop menjadi lebih kompleks.


Saya pikir alasan saya tidak pernah menggunakannya untuk ini adalah saya biasanya akhirnya memberi tahu pengguna apa yang salah dengan masukan mereka. Yang berarti kondisional akan berada di tengah loop dan saya akan hanya breakjika inputnya benar.
mphair

@mphair: Sebenarnya, untuk situasi seperti itu terkadang saya mungkin lebih cenderung menggunakan "lakukan {} while (0);" putaran, menggunakan "lanjutkan;" jika masukan pengguna tidak dapat diterima. Jika hanya ada satu masalah dan pesan, menggunakan "do {} while (1);" dan "istirahat;" berfungsi dengan baik, tetapi jika ada beberapa alasan untuk meminta masuk kembali, "lanjutkan;" membangun bekerja lebih baik.
supercat

2

Saya telah menggunakannya untuk pembaca yang membaca struktur yang sama beberapa kali.

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}

1

Saya telah menggunakan a do whileketika saya membaca nilai sentinel di awal file, tetapi selain itu, menurut saya tidak abnormal bahwa struktur ini tidak terlalu umum digunakan - do-whiles benar-benar situasional.

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)

1

Inilah teori saya mengapa kebanyakan orang (termasuk saya) lebih suka while () {} loop to do {} while (): A while () {} loop bisa dengan mudah disesuaikan untuk melakukan seperti do.. while () loop sedangkan sebaliknya tidak benar. A while loop dalam cara tertentu "lebih umum". Juga pemrogram menyukai pola yang mudah dipahami. A while loop mengatakan tepat di awal apa invariannya dan ini hal yang bagus.

Inilah yang saya maksud tentang hal "yang lebih umum". Lakukan ini do.. while loop:

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

Mengubah ini menjadi loop sementara sangat mudah:

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

Sekarang, kami mengambil model while loop:

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

Dan ubah ini menjadi do.. while loop, menghasilkan monstrositas ini:

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

Sekarang kami memiliki dua pemeriksaan di ujung yang berlawanan dan jika invarian berubah Anda harus memperbaruinya di dua tempat. Dengan cara tertentu lakukan..sementara itu seperti obeng khusus di kotak alat yang tidak pernah Anda gunakan, karena obeng standar melakukan semua yang Anda butuhkan.


1
Mengganti "do {} while (x);" memutar menjadi "while (x);" loop mensyaratkan bahwa X dapat berupa kondisi yang dapat dengan mudah "dipersiapkan", atau "secara alami" menjadi benar pada lintasan pertama. Bagi saya, pernyataan priming sebelum loop menyiratkan bahwa sesuatu dalam loop membutuhkan priming, dan while (x) {}; "loop menyiratkan bahwa loop dapat mengeksekusi nol kali. Jika saya ingin loop yang akan dieksekusi setidaknya sekali, saya gunakan loop "do {} while (x);".
supercat

1

Saya memprogram sekitar 12 tahun dan hanya 3 bulan yang lalu saya telah menemukan situasi di mana sangat nyaman untuk menggunakan do-while karena satu iterasi selalu diperlukan sebelum memeriksa suatu kondisi. Jadi tebaklah waktu besar Anda ada di depan :).


1
Hampir setiap kali saya melihat do ... sementara itu karena kurangnya pemahaman tentang masalah dan melibatkan beberapa peretasan yang mengerikan. Ada pengecualian, tetapi secara umum, jika Anda punya pekerjaan ... sementara, Anda harus memikirkan kembali apa yang Anda lakukan ... :-)
Brian Knoblauch

2
Jika Anda kemana-mana maka do-while akan dikeluarkan dari semua bahasa pemrograman agar tidak membingungkan programmer :).
Narek

@Narek: Sudah hampir tujuh tahun lagi sejak Anda menulis ini, apakah Anda memiliki lebih banyak keadaan di mana do whilesolusi yang lebih baik tanpa penyesalan?
chqrlie

Ya, mungkin sekali lagi: D
Narek

1

Saya tidak bisa membayangkan bagaimana Anda pergi selama ini tanpa menggunakan do...whileloop.

Ada satu di monitor lain sekarang dan ada beberapa loop seperti itu di program itu. Semuanya dalam bentuk:

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());

1

Ini adalah struktur yang cukup umum di server / konsumen:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work)
      do what is supposed to be done at end of busy period.
   ENDIF
ENDDO

yang REPEAT UNTIL(cond)menjadido {...} while(!cond)

Terkadang menunggu untuk bekerja (0) bisa jadi lebih murah dari segi CPU (bahkan menghilangkan penghitungan batas waktu mungkin merupakan peningkatan dengan tingkat kedatangan yang sangat tinggi). Selain itu, banyaknya hasil teori antrian yang menjadikan nomor yang dilayani pada masa sibuk menjadi statistik penting. (Lihat misalnya Kleinrock - Vol 1.)

Demikian pula:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work)
   ENDIF
   check for and do other (perhaps polled) work.
ENDDO

di mana check for and do other workmungkin sangat mahal untuk dimasukkan ke dalam loop utama atau mungkin kernel yang tidak mendukung waitany(waitcontrol*,n)operasi tipe yang efisien atau mungkin situasi di mana antrian yang diprioritaskan mungkin membuat pekerjaan lain kelaparan dan throttle digunakan sebagai kontrol kelaparan.

Jenis penyeimbangan ini bisa tampak seperti peretasan, tetapi mungkin perlu. Penggunaan kumpulan utas secara buta akan sepenuhnya mengalahkan manfaat kinerja dari penggunaan utas pengurus dengan antrean pribadi untuk struktur data rumit dengan tingkat pembaruan tinggi karena penggunaan kumpulan utas daripada utas pengurus akan membutuhkan implementasi aman utas.

Saya benar-benar tidak ingin berdebat tentang kode semu (misalnya, apakah shutdown yang diminta harus diuji dalam SAMPAI) atau utas pengurus versus kumpulan utas - ini hanya dimaksudkan untuk memberikan gambaran tentang kasus penggunaan tertentu struktur aliran kontrol.


1

Ini adalah pendapat pribadi saya, tetapi pertanyaan ini meminta jawaban yang berakar pada pengalaman:

  • Saya telah memprogram dalam C selama 38 tahun, dan saya tidak pernah menggunakan do/ whileloop dalam kode biasa.

  • Satu-satunya penggunaan yang menarik untuk konstruksi ini ada di makro tempat ia bisa menggabungkan beberapa pernyataan menjadi satu pernyataan melalui a do { multiple statements } while (0)

  • Saya telah melihat banyak contoh do/ whileloop dengan deteksi kesalahan palsu atau panggilan fungsi yang berlebihan.

  • Penjelasan saya untuk pengamatan ini adalah programmer cenderung memodelkan masalah secara tidak benar ketika mereka berpikir dalam istilah do/ whileloop. Mereka kehilangan kondisi akhir yang penting atau mereka kehilangan kemungkinan kegagalan dari kondisi awal yang mereka pindah ke akhir.

Karena alasan ini, saya menjadi yakin bahwa di mana ada do/ whileloop, ada bug , dan saya secara teratur menantang programmer pemula untuk menunjukkan kepada saya do/while loop di mana saya tidak dapat menemukan bug di sekitar.

Jenis loop ini dapat dengan mudah dihindari: gunakan a for (;;) { ... }dan tambahkan tes terminasi yang diperlukan jika sesuai. Sangat umum bahwa diperlukan lebih dari satu tes semacam itu.

Berikut ini contoh klasiknya:

/* skip the line */
do {
    c = getc(fp);
} while (c != '\n');

Ini akan gagal jika file tidak diakhiri dengan baris baru. Contoh sepele dari file semacam itu adalah file kosong.

Versi yang lebih baik adalah ini:

int c;  // another classic bug is to define c as char.
while ((c = getc(fp)) != EOF && c != '\n')
    continue;

Bergantian, versi ini juga menyembunyikan cvariabel:

for (;;) {
    int c = getc(fp);
    if (c == EOF || c == '\n')
        break;
}

Coba cari while (c != '\n');di mesin pencari mana saja, dan Anda akan menemukan bug seperti ini (diambil 24 Juni 2017):

Di ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c , function getword(stream,p,ignore), memiliki do/ whiledan cukup yakin setidaknya 2 bug:

  • cdidefinisikan sebagai chardan
  • ada potensi putaran tak terbatas while (c!='\n') c=getc(stream);

Kesimpulan: hindari do/ whileloop dan cari bug saat Anda melihatnya.


1
Saya lebih suka menghindari while() {}loop, karena lebih aman dalam hal pemeriksaan awal, sehingga cenderung membuat Anda "tidak fokus", malas memikirkan algoritme yang lebih baik, melakukan banyak pengecekan kesalahan yang tidak perlu, dst .. "Kurangnya do{}while()penggunaan" adalah pertanda buruk (tidak berotak) atau programmer pemula, menghasilkan kualitas yang lebih rendah dan kode yang lebih lambat. Jadi saya pertama kali bertanya pada diri sendiri "Apakah ini kasus ketat () {}?" Jika tidak - Saya hanya akan mencoba menulis do while loop, meskipun itu mungkin memerlukan pemikiran lebih dan akurasi data input
xakepp35

Saya memahami jawaban Anda, tetapi saya dapat memikirkan beberapa kemungkinan skenario di mana hal ini sebenarnya akan lebih baik. Silakan lihat while: prnt.sc/v2zy04 atau di do while: prnt.sc/v2zyka . Saya belum menjadi programmer selama Anda, tetapi saya tidak dapat menemukan bug di sana. Cukup jelas bahwa do while lebih bersih karena tidak memerlukan pemeriksaan ekstra saat memasuki loop. Jika kita berbicara tentang mengoptimalkan kode maka menurut saya itu cukup bersih.
Roy Berris

@RoyBerris: contoh Anda menarik. Dalam program C, fungsi yang digunakan di dalam loop akan membutuhkan tes tambahan untuk memastikan mereka tidak gagal. Ini akan menambah kekacauan dan breakatau returnpernyataan ekstra . Mengubah do/ whileloop menjadi for(;;)loop menjadi IMHO lebih konsisten. Pengucilan saya terhadap pernyataan ini mirip dengan penolakan saya untuk menggunakan strncpy() bahkan dalam kasus yang jarang terjadi di mana itu akan menjadi alat yang tepat: jangan biarkan pembaca biasa membayangkan bahwa konstruksi ini tidak berbahaya, karena dalam kebanyakan kasus mereka adalah sumber bug yang sulit ditemukan .
chqrlie

@chqrlie melihat jawaban aslinya adalah tentang bahasa C apa pun, saya kira kedua jawaban akan dilakukan. C # jauh lebih "hemat" dibanding pendahulunya, jadi secara teknis akan lebih cepat dengan melakukan sementara.
Roy Berris

0

whileloop memeriksa kondisi sebelum loop, do...whileloop memeriksa kondisi setelah loop. Ini berguna jika Anda ingin mendasarkan kondisi pada efek samping dari loop yang sedang berjalan atau, seperti yang dikatakan poster lain, jika Anda ingin loop berjalan setidaknya sekali.

Saya mengerti dari mana Anda berasal, tetapi do-whileini adalah sesuatu yang paling jarang digunakan, dan saya sendiri tidak pernah menggunakannya. Anda tidak melakukannya dengan salah.

Anda tidak melakukannya dengan salah. Itu seperti mengatakan seseorang melakukan kesalahan karena mereka tidak pernah menggunakan yang byteprimitif. Hanya saja tidak begitu umum digunakan.


0

Skenario paling umum yang saya temui di mana saya menggunakan do/ whileloop adalah dalam program konsol kecil yang berjalan berdasarkan beberapa input dan akan berulang sebanyak yang diinginkan pengguna. Jelas tidak masuk akal untuk program konsol untuk berjalan tanpa waktu; tetapi setelah pertama kali, terserah pengguna - karenanya do/ whilebukan hanya while.

Ini memungkinkan pengguna untuk mencoba banyak input berbeda jika diinginkan.

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

Saya menduga bahwa pengembang perangkat lunak menggunakan do/ whilesemakin sedikit hari ini, sekarang hampir setiap program di bawah matahari memiliki semacam GUI. Ini lebih masuk akal dengan aplikasi konsol, karena ada kebutuhan untuk terus menyegarkan keluaran untuk memberikan instruksi atau meminta pengguna dengan informasi baru. Sebaliknya, dengan GUI, teks yang memberikan informasi tersebut kepada pengguna dapat hanya duduk di formulir dan tidak perlu diulang secara terprogram.


0

Saya menggunakan loop do-while sepanjang waktu saat membaca dalam file. Saya bekerja dengan banyak file teks yang menyertakan komentar di header:

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

saya akan menggunakan loop do-while untuk membaca baris "kolom1 kolom2" sehingga saya dapat mencari kolom yang diinginkan. Inilah pseudocode-nya:

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

Kemudian saya akan melakukan loop sementara untuk membaca seluruh file.


Mendukung komentar di mana saja dalam file akan menjadi sepele (dan menyederhanakan kode secara keseluruhan) jika Anda meletakkan if (line[0]=='#') continue;tepat setelah read_linepanggilan di loop utama Anda ...
R .. GitHub STOP HELPING ICE

Saya tidak dapat melihat bagaimana saya akan menerapkan saran Anda untuk menemukan tajuk. (dang, tidak tahu cara memformat kode di komentar, tolong bantu!) header = false; while (! header) {line = read_line (); jika (baris [0] == '#') lanjutkan; header = true; } ini lebih jelas / sederhana bagi Anda?
terbang

0

Menjadi programmer tua, banyak proyek pemrograman sekolah saya menggunakan interaksi yang didorong menu teks. Hampir semua menggunakan sesuatu seperti logika berikut untuk prosedur utama:

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

Sejak masa sekolah, saya telah menemukan bahwa saya menggunakan loop sementara lebih sering.


0

Salah satu aplikasi yang saya lihat ada di Oracle ketika kita melihat kumpulan hasil.

Setelah Anda memiliki kumpulan hasil, pertama-tama Anda mengambil darinya (lakukan) dan sejak saat itu .. periksa apakah pengambilan mengembalikan elemen atau tidak (saat elemen ditemukan ..) .. Hal yang sama mungkin berlaku untuk yang lain " fetch-like ".


0

Saya telah menggunakannya dalam fungsi yang mengembalikan posisi karakter berikutnya dalam string utf-8:

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

Perhatikan bahwa, fungsi ini ditulis dari pikiran dan tidak diuji. Intinya adalah Anda harus melakukan langkah pertama dan Anda harus melakukannya sebelum Anda dapat mengevaluasi kondisinya.


Itu cara menulis yang buruk *(unsigned char *)txt-0x80U<0x40.
R .. GitHub STOP HELPING ICE

0

Semua jenis input konsol bekerja dengan baik dengan do-while karena Anda meminta pertama kali, dan meminta ulang setiap kali validasi input gagal.


0

Meskipun ada banyak jawaban di sini saya ambil. Semuanya bermuara pada optimalisasi. Saya akan menunjukkan dua contoh di mana yang satu lebih cepat dari yang lainnya.

Kasus 1: while

string fileName = string.Empty, fullPath = string.Empty;

while (string.IsNullOrEmpty(fileName) || File.Exists(fullPath))
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}

Kasus 2: do while

string fileName = string.Empty, fullPath = string.Empty;

do
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}
while (File.Exists(fullPath));

Jadi ada dua orang yang akan melakukan hal yang persis sama. Tetapi ada satu perbedaan mendasar dan bahwa while membutuhkan pernyataan tambahan untuk memasukkan while. Yang jelek karena katakanlah setiap kemungkinan skenario Guidkelas telah diambil kecuali satu varian. Ini berarti saya harus mengulang-ulang 5,316,911,983,139,663,491,615,228,241,121,400,000waktu. Setiap kali saya sampai di akhir pernyataan while saya, saya perlu melakukan string.IsNullOrEmpty(fileName)pemeriksaan. Jadi ini akan memakan sedikit, sebagian kecil dari pekerjaan CPU. Tetapi apakah tugas yang sangat kecil ini dikalikan dengan kemungkinan kombinasi yang dimiliki Guidkelas dan kita berbicara tentang jam, hari, bulan, atau waktu tambahan?

Tentu saja ini adalah contoh ekstrim karena Anda mungkin tidak akan melihatnya dalam produksi. Tetapi jika kita berpikir tentang algoritme YouTube, sangat mungkin mereka akan menemukan pembuatan ID di mana beberapa ID telah diambil. Jadi itu tergantung pada proyek besar dan optimalisasi.


0

Saya ingin memahami keduanya sebagai:
while-> 'ulangi sampai',
do ... while-> 'ulangi jika'.


-1

Saya menemukan ini saat meneliti loop yang tepat untuk digunakan untuk situasi yang saya alami. Saya percaya ini akan sepenuhnya memenuhi situasi umum di mana do .. while loop adalah implementasi yang lebih baik daripada while loop (bahasa C #, karena Anda menyatakan itu adalah pekerjaan utama Anda).

Saya membuat daftar string berdasarkan hasil kueri SQL. Objek yang dikembalikan oleh kueri saya adalah SQLDataReader. Objek ini memiliki fungsi yang disebut Read () yang memajukan objek ke baris data berikutnya, dan mengembalikan nilai true jika ada baris lain. Ini akan mengembalikan false jika tidak ada baris lain.

Dengan menggunakan informasi ini, saya ingin mengembalikan setiap baris ke daftar, lalu berhenti jika tidak ada lagi data untuk dikembalikan. A Do ... While loop bekerja paling baik dalam situasi ini karena memastikan bahwa menambahkan item ke daftar akan terjadi SEBELUM memeriksa apakah ada baris lain. Alasan ini harus dilakukan SEBELUM memeriksa while (kondisi) adalah karena ketika diperiksa, ia juga maju. Menggunakan loop sementara dalam situasi ini akan menyebabkannya melewati baris pertama karena sifat dari fungsi tersebut.

Pendeknya:

Ini tidak akan berhasil dalam situasi saya.

    //This will skip the first row because Read() returns true after advancing.
    while (_read.NextResult())
           {
               list.Add(_read.GetValue(0).ToString());
           }

   return list;

Ini akan.

    //This will make sure the currently read row is added before advancing.
    do
        {
            list.Add(_read.GetValue(0).ToString());
        } 
        while (_read.NextResult());

    return list;

Penggunaan SQLDataReader akan menjadi loop bersarang. Bagian dalam memanggil Read()dan harus loop sementara, karena Read()panggilan pertama mengakses baris pertama. Yang terluar memanggil NextResult()dan harus menjadi do-while, karena dataset hasil pertama aktif sebelum NextResult()panggilan pertama . Potongan kode tidak masuk akal, terutama karena komentar keduanya tidak cocok dengan kode dan salah.
Ben Voigt

-1
Console.WriteLine("hoeveel keer moet je de zin schrijven?");
        int aantal = Convert.ToInt32(Console.ReadLine());
        int counter = 0;

        while ( counter <= aantal)
        {
            Console.WriteLine("Ik mag geen stiften gooien");
            counter = counter + 1;

Anda harus menjawab pertanyaan Anda sendiri seolah-olah Anda akan menjawab pertanyaan orang lain. Termasuk penjelasan serta kode
Simon
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.