Perbedaan antara "coroutine" dan "thread"?


Jawaban:


122

Coroutine adalah bentuk pemrosesan sekuensial: hanya satu yang mengeksekusi pada waktu tertentu (seperti prosedur subrutin AKA, fungsi AKA - mereka hanya melewati tongkat di antara satu sama lain dengan lebih lancar).

Utas (setidaknya secara konseptual) merupakan bentuk pemrosesan bersamaan: beberapa utas dapat dijalankan pada waktu tertentu. (Secara tradisional, pada CPU tunggal, mesin single-core, konkurensi disimulasikan dengan bantuan dari OS - saat ini, karena begitu banyak mesin multi-CPU dan / atau multi-core, utas akan secara de facto dieksekusi secara bersamaan, bukan hanya "secara konseptual").


188

Pertama kali dibaca: Concurrency vs Parallelism - Apa bedanya?

Concurrency adalah pemisahan tugas untuk memberikan eksekusi yang disisipkan. Paralelisme adalah eksekusi simultan dari beberapa bagian pekerjaan untuk meningkatkan kecepatan. - https://github.com/servo/servo/wiki/Design

Jawaban singkat: Dengan utas, sistem operasi mengalihkan utas yang berjalan terlebih dahulu sesuai dengan penjadwalnya, yang merupakan algoritme dalam kernel sistem operasi. Dengan coroutine, programmer dan bahasa pemrograman menentukan kapan harus mengganti coroutine; dengan kata lain, tugas secara multitugas kooperatif dengan menjeda dan melanjutkan fungsi pada titik setel, biasanya (tetapi tidak harus) dalam satu utas.

Jawaban panjang: Berbeda dengan utas, yang dijadwalkan sebelumnya oleh sistem operasi, sakelar coroutine kooperatif, artinya pemrogram (dan mungkin bahasa pemrograman dan runtime) mengontrol kapan sakelar akan terjadi.

Berbeda dengan utas, yang bersifat pre-emptive, sakelar coroutine bersifat kooperatif (pemrogram mengontrol kapan sakelar akan terjadi). Kernel tidak terlibat dalam sakelar coroutine. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

Bahasa yang mendukung utas asli dapat menjalankan utasnya (utas pengguna) pada utas sistem operasi ( utas kernel ). Setiap proses memiliki setidaknya satu utas kernel. Utas kernel seperti proses, kecuali bahwa mereka berbagi ruang memori dalam proses kepemilikannya dengan semua utas lainnya dalam proses itu. Suatu proses "memiliki" semua sumber daya yang ditugaskan, seperti memori, pegangan file, soket, pegangan perangkat, dll., Dan sumber daya ini semuanya dibagi di antara utas kernelnya.

Penjadwal sistem operasi adalah bagian dari kernel yang menjalankan setiap utas untuk jangka waktu tertentu (pada mesin prosesor tunggal). Penjadwal mengalokasikan waktu (timelicing) untuk setiap utas, dan jika utas tidak selesai dalam waktu itu, penjadwal mendahului itu (menyela dan beralih ke utas lain). Beberapa utas dapat berjalan secara paralel pada mesin multi-prosesor, karena setiap utas dapat (tetapi tidak harus harus) dijadwalkan ke prosesor yang terpisah.

Pada mesin prosesor tunggal, utas dikali waktu dan didahului (beralih di antara) dengan cepat (di Linux kutu waktu default adalah 100 ms) yang membuatnya bersamaan. Namun, mereka tidak dapat dijalankan secara paralel (bersamaan), karena prosesor single-core hanya dapat menjalankan satu hal pada satu waktu.

Coroutine dan / atau generator dapat digunakan untuk mengimplementasikan fungsi kerja sama. Alih-alih dijalankan pada utas kernel dan dijadwalkan oleh sistem operasi, mereka berjalan dalam satu utas sampai menghasilkan atau selesai, menghasilkan ke fungsi lain yang ditentukan oleh programmer. Bahasa dengan generator , seperti Python dan ECMAScript 6, dapat digunakan untuk membangun coroutine. Async / await (terlihat dalam C #, Python, ECMAscript 7, Rust) adalah abstraksi yang dibangun di atas fungsi generator yang menghasilkan masa depan / janji.

Dalam beberapa konteks, coroutine dapat merujuk ke fungsi stackful sedangkan generator dapat merujuk ke fungsi stackless.

Serat , benang ringan , dan benang hijau adalah nama lain untuk coroutine atau hal-hal seperti coroutine. Mereka kadang-kadang terlihat (biasanya sengaja) lebih seperti utas sistem operasi dalam bahasa pemrograman, tetapi mereka tidak berjalan secara paralel seperti utas nyata dan berfungsi sebagai coroutine. (Mungkin ada kekhasan teknis yang lebih spesifik atau perbedaan di antara konsep-konsep ini tergantung pada bahasa atau implementasinya.)

Misalnya, Java memiliki " utas hijau "; ini adalah utas yang dijadwalkan oleh mesin virtual Java (JVM) alih-alih secara bawaan pada utas kernel sistem operasi yang mendasarinya. Ini tidak berjalan secara paralel atau mengambil keuntungan dari banyak prosesor / core - karena itu akan memerlukan thread asli! Karena mereka tidak dijadwalkan oleh OS, mereka lebih seperti coroutine daripada utas kernel. Thread hijau adalah apa yang digunakan Java sampai thread asli diperkenalkan ke Java 1.2.

Thread mengkonsumsi sumber daya. Dalam JVM, setiap utas memiliki tumpukan sendiri, biasanya berukuran 1MB. 64k adalah jumlah ruang stack paling sedikit yang diizinkan per utas di JVM. Ukuran tumpukan ulir dapat dikonfigurasi pada baris perintah untuk JVM. Terlepas dari namanya, utas tidak gratis, karena sumber daya penggunaannya seperti setiap utas yang membutuhkan tumpukan sendiri, penyimpanan utas-lokal (jika ada), dan biaya penjadwalan utas / penukaran konteks / pembatalan cache CPU. Ini adalah bagian dari alasan mengapa coroutine telah menjadi populer untuk aplikasi yang kritis dan sangat bersamaan.

Mac OS hanya akan memungkinkan proses untuk mengalokasikan sekitar 2000 utas, dan Linux mengalokasikan 8MB tumpukan per utas dan hanya akan memungkinkan sebanyak utas yang sesuai dengan RAM fisik.

Karenanya, utas adalah bobot terberat (dalam hal penggunaan memori dan waktu pengalihan konteks), lalu coroutine, dan akhirnya generator adalah bobot paling ringan.


2
+1, tetapi jawaban ini dapat memanfaatkan beberapa referensi.
kojiro

1
Benang hijau adalah sesuatu yang berbeda dari coroutine. bukan? Bahkan serat memiliki beberapa perbedaan. lihat programmers.stackexchange.com/questions/254140/…

113

Sekitar 7 tahun terlambat, tetapi jawaban di sini tidak ada konteks pada ko-rutin vs utas. Mengapa coroutine menerima begitu banyak perhatian belakangan ini, dan kapan saya akan menggunakannya dibandingkan dengan utas ?

Pertama-tama jika coroutine berjalan secara bersamaan (tidak pernah paralel ), mengapa ada orang yang lebih suka daripada thread?

Jawabannya adalah coroutine dapat memberikan tingkat konkurensi yang sangat tinggi dengan overhead yang sangat kecil . Secara umum di lingkungan berulir Anda memiliki paling banyak 30-50 utas sebelum jumlah overhead terbuang sebenarnya penjadwalan utas ini (oleh penjadwal sistem) secara signifikan memotong jumlah waktu ulir benar-benar melakukan pekerjaan yang bermanfaat.

Ok jadi dengan utas Anda dapat memiliki paralelisme, tetapi tidak terlalu banyak paralelisme, bukankah itu masih lebih baik daripada co-rutin berjalan dalam satu utas? Yah belum tentu. Ingat co-rutin masih dapat melakukan konkurensi tanpa overhead scheduler - itu hanya mengelola konteks-switching itu sendiri.

Sebagai contoh jika Anda memiliki rutin melakukan beberapa pekerjaan dan melakukan operasi yang Anda tahu akan diblokir untuk beberapa waktu (yaitu permintaan jaringan), dengan co-rutin Anda dapat segera beralih ke rutin lain tanpa biaya tambahan termasuk penjadwal sistem dalam keputusan ini - ya Anda, programmer harus menentukan kapan co-rutin dapat beralih.

Dengan banyak rutinitas melakukan pekerjaan yang sangat kecil dan secara sukarela beralih di antara yang lain, Anda telah mencapai tingkat efisiensi yang tidak bisa dicapai oleh penjadwal. Anda sekarang dapat memiliki ribuan coroutine yang bekerja bersama sebagai lawan dari puluhan utas.

Karena rutinitas Anda sekarang beralih satu sama lain sebagai titik yang telah ditentukan sebelumnya, kini Anda juga dapat menghindari mengunci pada struktur data yang dibagikan (karena Anda tidak akan pernah memberi tahu kode Anda untuk beralih ke coroutine lain di tengah bagian kritis)

Manfaat lain adalah penggunaan memori yang jauh lebih rendah. Dengan model berulir, setiap utas perlu mengalokasikan tumpukannya sendiri, sehingga penggunaan memori Anda tumbuh secara linier dengan jumlah utas yang Anda miliki. Dengan co-rutin, jumlah rutin yang Anda miliki tidak memiliki hubungan langsung dengan penggunaan memori Anda.

Dan akhirnya, co-rutin menerima banyak perhatian karena dalam beberapa bahasa pemrograman (seperti Python) utas Anda tidak dapat berjalan secara paralel - mereka berjalan secara bersamaan seperti coroutine, tetapi tanpa memori rendah dan penjadwalan bebas biaya overhead.


2
Bagaimana cara beralih ke tugas lain di coroutine ketika kita menghadapi operasi pemblokiran?
Narcisse Doudieu Siewe

Cara Anda beralih ke tugas lain adalah membuat operasi pemblokiran benar-benar dilakukan async. Ini berarti Anda harus menghindari penggunaan operasi apa pun yang benar-benar akan diblokir, dan hanya menggunakan operasi yang mendukung tidak memblokir ketika digunakan dalam sistem coroutine Anda. Satu-satunya cara untuk mengatasi hal ini adalah dengan memiliki coroutine yang didukung oleh kernel, seperti UMS pada Windows misalnya, di mana ia melompat ke penjadwal Anda setiap kali "utas" UMS Anda memblokir pada syscall.
retep998

@ MartinKonecny ​​Apakah TS Thread C ++ terbaru mengikuti pendekatan yang Anda sebutkan?
Nikos

Jadi pada akhirnya bahasa pemrograman modern akan membutuhkan Coroutine / Fibers untuk secara efisien memanfaatkan inti CPU tunggal untuk mis. Operasi non-komputasi-berat seperti IO dan Threads untuk memparalelkan operasi intensif CPU pada banyak core untuk mendapatkan kecepatan, bukan?
Mahatma_Fatal_Error

19

Dalam satu kata: preemption. Coroutine bertindak seperti pemain sulap yang saling berbagi poin dengan latihan yang baik. Thread (true threads) dapat terputus di hampir semua titik dan kemudian dilanjutkan kembali. Tentu saja, ini membawa segala macam masalah konflik sumber daya, karenanya GIL terkenal Python - Global Interpreter Lock.

Banyak implementasi utas sebenarnya lebih seperti coroutine.


9

Itu tergantung pada bahasa yang Anda gunakan. Sebagai contoh dalam Lua mereka adalah hal yang sama (tipe variabel dari coroutine disebut thread).

Biasanya meskipun coroutine menerapkan hasil sukarela di mana (Anda) programmer memutuskan ke mana yield, yaitu, memberikan kontrol untuk rutin lain.

Threads sebaliknya dikelola secara otomatis (dihentikan dan dimulai) oleh OS, dan mereka bahkan dapat berjalan pada saat yang sama pada CPU multicore.


0

12 Tahun terlambat untuk diskusi tetapi coroutine memiliki penjelasan atas namanya. Coroutine dapat diuraikan menjadi Co dan Rutin.

Rutin dalam konteks ini hanyalah urutan operasi / tindakan dan dengan menjalankan / memproses rutin urutan operasi dijalankan satu per satu dalam urutan yang sama persis seperti yang ditentukan.

Co adalah singkatan dari kerjasama. Co rutin diminta untuk (atau lebih baik diharapkan) dengan sukarela menunda eksekusi untuk memberikan co-rutin lain kesempatan untuk mengeksekusi juga. Jadi co-rutin adalah tentang berbagi sumber daya CPU (dengan sukarela) sehingga orang lain dapat menggunakan sumber daya yang sama seperti yang digunakan sendiri.

Utas di sisi lain tidak perlu menunda eksekusi. Ditangguhkan sepenuhnya transparan pada utas dan utas dipaksa oleh perangkat keras yang mendasarinya untuk ditangguhkan sendiri. Hal ini juga dilakukan sedemikian rupa sehingga sebagian besar transparan ke utas karena tidak mendapatkan pemberitahuan dan keadaan itu tidak diubah tetapi disimpan dan kemudian dipulihkan ketika utas dibiarkan berlanjut.

Satu hal yang tidak benar, bahwa co-rutinitas tidak dapat dilakukan bersamaan dan kondisi balapan tidak dapat terjadi. Itu tergantung pada sistem yang menjalankan co-rutin dan mudah untuk pencitraan co-rutin.

Tidak masalah bagaimana co-rutin menangguhkan diri. Kembali di Windows 3.1 int 03 dijalin ke dalam program apa pun (atau harus ditempatkan di sana) dan di C # kami menambahkan hasil.

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.