Apa perbedaan antara coroutine dan utas? Apakah ada keuntungan menggunakan satu di atas yang lain?
Apa perbedaan antara coroutine dan utas? Apakah ada keuntungan menggunakan satu di atas yang lain?
Jawaban:
Sementara Coroutine tampaknya bekerja seperti utas pada pandangan pertama, mereka sebenarnya tidak menggunakan multithreading. Mereka dieksekusi secara berurutan sampai mereka yield
. Mesin akan memeriksa semua coroutine yang dihasilkan sebagai bagian dari loop utama sendiri (pada titik apa tepatnya tergantung pada jenis yield
, periksa diagram ini untuk informasi lebih lanjut ), lanjutkan satu per satu hingga berikutnya yield
, dan kemudian lanjutkan dengan loop utama.
Teknik ini memiliki keuntungan bahwa Anda dapat menggunakan coroutine tanpa sakit kepala yang disebabkan oleh masalah multithreading nyata. Anda tidak akan mendapatkan kebuntuan, kondisi balapan, atau masalah kinerja yang disebabkan oleh sakelar konteks, Anda akan dapat melakukan debug dengan benar dan Anda tidak perlu menggunakan wadah data yang aman. Ini karena ketika coroutine dijalankan, mesin Unity dalam keadaan terkendali. Aman untuk menggunakan sebagian besar fungsi Unity.
Dengan utas, di sisi lain, Anda sama sekali tidak memiliki pengetahuan tentang status loop utama Unity saat ini (mungkin sebenarnya tidak lagi berjalan sama sekali). Jadi utas Anda dapat menyebabkan banyak kekacauan dengan melakukan sesuatu pada suatu waktu yang seharusnya tidak melakukan hal itu. Jangan menyentuh fungsionalitas Unity asli apa pun dari sub-utas . Jika Anda perlu berkomunikasi antara sub-utas dan utas utama Anda, minta utasnya menulis ke beberapa objek-wadah yang aman (!) Dan minta MonoBehaviour membaca informasi itu selama fungsi acara Persatuan yang biasa.
Kerugian dari tidak melakukan multithreading "nyata" adalah Anda tidak dapat menggunakan coroutine untuk memparalelkan perhitungan intensif CPU pada beberapa core CPU. Anda dapat menggunakannya, untuk membagi perhitungan menjadi beberapa pembaruan. Jadi, alih-alih membekukan game Anda selama satu detik, Anda hanya mendapatkan framerate rata-rata yang lebih rendah selama beberapa detik. Tetapi dalam hal ini Anda bertanggung jawab untuk yield
coroutine Anda setiap kali Anda ingin mengizinkan Unity untuk menjalankan pembaruan.
Kesimpulan:
Coroutine adalah apa yang kita dalam Ilmu Komputer sebut "multitasking kooperatif." Mereka adalah cara untuk berbagai aliran eksekusi untuk saling berhubungan satu sama lain secara kooperatif. Dalam kerja sama multitasking, satu aliran eksekusi memiliki satu-satunya kepemilikan CPU yang tak terbantahkan hingga mencapai a yield
. Pada titik itu, Unity (atau kerangka kerja apa pun yang Anda gunakan), memiliki opsi untuk beralih ke aliran eksekusi yang berbeda. Itu kemudian juga mendapatkan kepemilikan tak terbantahkan dari CPU sampai itu yield
.
Utas adalah apa yang kita sebut "preemptive multitasking." Saat Anda menggunakan utas, kerangka kerja berhak kapan saja untuk menghentikan utas Anda sebelum-pikir dan beralih ke utas lain. Tidak masalah di mana Anda berada. Dalam beberapa kasus Anda bahkan dapat dihentikan dengan menulis variabel ke memori!
Ada pro dan kontra untuk masing-masing. Kontra coroutine mungkin yang paling mudah dipahami. Pertama, semua coroutine dijalankan pada satu inti. Jika Anda memiliki CPU quad core, coroutine hanya akan menggunakan salah satu dari empat core. Ini menyederhanakan banyak hal, tetapi dapat menjadi masalah kinerja dalam beberapa kasus. Yang kedua adalah Anda harus menyadari bahwa coroutine apa pun dapat menghentikan seluruh program Anda hanya dengan menolaknya yield
. Ini adalah masalah pada Mac OS9, bertahun-tahun yang lalu. OS9 hanya mendukung multitasking kooperatif, di seluruh komputer. Jika salah satu program Anda macet, itu bisa menghentikan komputer dengan sangat keras sehingga OS bahkan tidak bisa membuat teks pesan kesalahan untuk memberi tahu Anda apa yang terjadi!
Kelebihan coroutine adalah bahwa mereka relatif mudah dimengerti. Kesalahan yang Anda miliki jauh lebih mudah diprediksi. Mereka juga biasanya meminta lebih sedikit sumber daya, yang dapat membantu saat Anda naik ke 10 dari ribuan coroutine atau utas. Candid Moon menyebutkan dalam komentar bahwa, jika Anda belum mempelajari utas dengan benar, patuhi coroutine, dan itu benar. Coroutine jauh lebih mudah untuk dikerjakan.
Utas adalah binatang yang sepenuhnya berbeda. Anda harus selalu waspada terhadap kemungkinan bahwa utas lain dapat mengganggu Anda kapan sajadan mengacaukan data Anda. Pustaka Threading menyediakan seluruh rangkaian alat yang kuat untuk membantu Anda dalam hal ini, seperti mutex dan variabel kondisi yang membantu Anda memberi tahu OS ketika aman untuk menjalankan salah satu utas Anda yang lain dan saat tidak aman. Ada seluruh kursus yang didedikasikan untuk cara menggunakan alat ini dengan baik. Salah satu masalah terkenal yang muncul adalah "jalan buntu," yaitu ketika dua utas keduanya "macet" menunggu yang lain membebaskan beberapa sumber. Masalah lain, yang sangat penting bagi Unity, adalah bahwa banyak perpustakaan (seperti Unity) tidak dirancang untuk mendukung panggilan dari banyak utas. Anda dapat dengan mudah mematahkan kerangka kerja Anda jika Anda tidak memperhatikan panggilan mana yang diizinkan dan mana yang dilarang.
Alasan untuk kompleksitas ekstra ini sebenarnya sangat sederhana. Model multitasking preemptive sangat mirip dengan model multithreading yang memungkinkan Anda untuk tidak hanya mengganggu thread lain, tetapi untuk benar-benar menjalankan thread berdampingan pada core yang berbeda. Ini sangat kuat, menjadi satu-satunya cara untuk benar-benar memanfaatkan CPU quad core dan hex code baru yang keluar, tetapi membuka kotak pandoras. Aturan sinkronisasi untuk cara mengelola data ini di dunia multithreading sangat brutal. Di dunia C ++, ada seluruh artikel yang didedikasikan untuk MEMORY_ORDER_CONSUME
satu sudut itty-bitty-teeny-weenie sinkronisasi multithreading.
Jadi kontra dari threading? Sederhana: sulit. Anda dapat menemukan seluruh kelas bug yang belum pernah Anda lihat sebelumnya. Banyak yang disebut "heisenbugs" yang terkadang muncul, dan kemudian menghilang ketika Anda men-debug mereka. Alat yang diberikan kepada Anda untuk menangani ini sangat kuat, tetapi juga sangat rendah. Mereka dirancang untuk menjadi efisien pada arsitektur chip modern daripada dirancang agar mudah digunakan.
Namun, jika Anda ingin menggunakan semua daya CPU Anda, itu adalah alat yang Anda butuhkan. Juga, ada yang benar-benar algoritma yang lebih mudah untuk memahami dalam multithreading daripada mereka dengan coroutines hanya karena Anda membiarkan OS menangani semua pertanyaan dari mana gangguan dapat terjadi.
Komentar Candid Moon untuk tetap pada coroutine adalah rekomendasi saya juga. Jika Anda menginginkan kekuatan utas, maka komitlah untuk itu. Pergi keluar dan benar-benar belajar benang, secara resmi. Kami memiliki beberapa dekade untuk mencari tahu bagaimana mengatur cara terbaik untuk memikirkan tentang utas sehingga Anda mendapatkan hasil yang dapat diulang dengan andal lebih awal, dan menambah kinerja saat Anda mulai. Misalnya, semua mata kuliah waras akan mengajarkan mutex sebelum mengajarkan variabel kondisi. Semua program waras yang membahas atom akan sepenuhnya mengajarkan mutasi dan variabel kondisi bahkan sebelum menyebutkan bahwa atom itu ada. (Catatan: tidak ada yang namanya tutorial waras tentang atom.) Cobalah belajar sedikit demi sedikit, dan Anda meminta migrain.
join()
, tetapi Anda memang membutuhkan sesuatu. Jika Anda tidak memiliki arsitek yang merancang sistem untuk melakukan sinkronisasi untuk Anda, Anda harus menulis sendiri. Sebagai seseorang yang melakukan banyak hal multithreaded, saya menemukan bahwa model mental orang tentang bagaimana komputer bekerja perlu menyesuaikan sebelum mereka melakukan sinkronisasi dengan aman (yang akan diajarkan oleh kursus yang baik)
join
. Maksud saya adalah mengejar fraksi moderat dari kemungkinan manfaat kinerja threading, mudah, kadang-kadang lebih baik daripada menggunakan pendekatan threading yang lebih rumit untuk menuai fraksi yang lebih besar.
Dalam istilah sesederhana mungkin ...
Utas
Sebuah thread tidak memutuskan kapan ia menghasilkan, sistem operasi ('OS', misalnya Windows) memutuskan kapan sebuah thread dihasilkan. Sistem operasi hampir sepenuhnya bertanggung jawab atas penjadwalan utas, ia memutuskan utas apa yang akan dijalankan, kapan harus menjalankannya dan berapa lama.
Selain itu utas mungkin dijalankan secara serempak (satu utas setelah yang lain) atau secara asinkron (utas berbeda berjalan pada core CPU yang berbeda). Kemampuan untuk berjalan secara asinkron berarti utas dapat menyelesaikan lebih banyak pekerjaan dalam jumlah waktu yang sama (karena utas secara harfiah melakukan dua hal pada saat yang sama). Bahkan utas sinkron dapat melakukan banyak pekerjaan jika OSnya bagus dalam menjadwalkannya.
Namun, kekuatan pemrosesan ekstra ini disertai dengan efek samping. Misalnya, jika dua utas sedang mencoba mengakses sumber daya yang sama (misalnya daftar) dan masing-masing utas dapat dihentikan secara acak di titik mana pun dalam kode, modifikasi utas kedua dapat mengganggu modifikasi yang dibuat oleh utas pertama. (Lihat juga: Kondisi Balapan dan Kebuntuan .)
Thread juga dianggap 'berat' karena mereka memiliki banyak overhead yang berarti ada penalti waktu yang cukup besar saat mengganti thread.
Coroutine
Tidak seperti utas, coroutine sepenuhnya sinkron, hanya satu coroutine yang dapat berjalan pada suatu titik waktu. Selain itu coroutine dapat memilih kapan untuk menghasilkan, dan dengan demikian dapat memilih untuk menghasilkan pada titik dalam kode yang convinient (misalnya pada akhir siklus loop). Ini memiliki keuntungan dari masalah seperti kondisi balapan dan kebuntuan yang lebih mudah untuk dihindari, serta memudahkan coroutine untuk bekerja sama satu sama lain.
Namun ini juga merupakan tanggung jawab utama, jika coroutine tidak menghasilkan dengan benar, itu bisa menghabiskan banyak waktu prosesor dan masih dapat menyebabkan bug jika memodifikasi sumber daya bersama secara tidak benar.
Coroutine umumnya tidak memerlukan pengalihan konteks dan karenanya cepat untuk masuk dan keluar dan cukup ringan.
Singkatnya:
Benang:
Coroutine:
Peran utas dan coroutine sangat mirip, tetapi mereka berbeda dalam bagaimana mereka menyelesaikan pekerjaan yang berarti bahwa masing-masing lebih cocok untuk tugas yang berbeda. Utas adalah yang terbaik untuk tugas-tugas di mana mereka dapat fokus melakukan sesuatu sendiri tanpa terganggu, lalu memberi sinyal kembali ketika sudah selesai. Coroutine adalah yang terbaik untuk tugas-tugas yang dapat dilakukan dalam banyak langkah kecil dan tugas-tugas yang membutuhkan pemrosesan data secara kooperatif.