“Koroutin” ve “iplik” arasındaki fark nedir?


Yanıtlar:


122

Koroutinler sıralı bir işleme biçimidir: herhangi bir zamanda sadece bir tanesi yürütülür (tıpkı AKA prosedürleri AKA'nın alt rutinleri gibi - sadece batonları birbirinden daha akıcı geçerler).

İş parçacıkları (en azından kavramsal olarak) bir eşzamanlı işleme biçimidir: herhangi bir zamanda birden çok iş parçacığı yürütülüyor olabilir. (Geleneksel olarak, tek CPU, tek çekirdekli makinelerde, bu eşzamanlılık işletim yardımıyla bazı simüle edilmiş - pek çok makina çok işlemci ve / veya çok çekirdekli çünkü günümüzde, lifler olacaktır fiilen , aynı anda yürütülmesi olmak sadece "kavramsal olarak" değil).


188

İlk okuma: Concurrency vs Parallelism - Fark nedir?

Eşzamanlılık, serpiştirilmiş yürütme sağlamak için görevlerin ayrılmasıdır. Paralellik, hızı arttırmak için birden fazla işin eşzamanlı olarak uygulanmasıdır. - https://github.com/servo/servo/wiki/Design

Kısa cevap: İş parçacıkları ile, işletim sistemi, iş parçacığı, işletim sistemi çekirdeğinde bir algoritma olan zamanlayıcısına göre önceden değiştirir. Programlar ile programcı ve programlama dili, programların ne zaman değiştirileceğini belirler; diğer bir deyişle, görevler, tipik olarak (ancak zorunlu olarak) tek bir iş parçacığı içinde ayar noktalarında işlevlerin duraklatılması ve sürdürülmesi ile birlikte çoklu görevler yerine getirilir.

Uzun cevap: İşletim sistemi tarafından önceden etkin bir şekilde planlanan iş parçacıklarının aksine, programcı anahtarlar işbirlikçidir, yani programcı (ve muhtemelen programlama dili ve çalışma zamanı) bir anahtarın ne zaman olacağını kontrol eder.

Önleyici olan iş parçacıklarının aksine, koroutin anahtarlar birlikte çalışır (bir anahtarın ne zaman olacağını programcı kontrol eder). Çekirdek, koroutin anahtarlara dahil değildir. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

Yerel iş parçacıklarını destekleyen bir dil parçacıklarını (kullanıcı iş parçacıkları) işletim sisteminin iş parçacığı ( çekirdek iş parçacıkları) üzerinde yürütebilir . Her işlemin en az bir çekirdek iş parçacığı vardır. Çekirdek iş parçacıkları, işlemlere benzer, ancak sahip olma işlemlerindeki bellek alanını bu işlemdeki diğer tüm iş parçacıkları ile paylaşırlar. Bir işlem, bellek, dosya tanıtıcıları, yuvalar, aygıt tanıtıcıları vb. Gibi atanmış tüm kaynaklara "sahiptir" ve bu kaynakların tümü çekirdek iş parçacıkları arasında paylaşılır.

İşletim sistemi zamanlayıcısı, her iş parçacığını belirli bir süre çalıştıran çekirdeğin bir parçasıdır (tek bir işlemci makinesinde). Zamanlayıcı her iş parçacığına zaman (zaman dilimleme) ayırır ve iş parçacığı bu süre içinde bitmezse, zamanlayıcı bunu önceden belirler (keser ve başka bir iş parçacığına geçer). Her iş parçacığı ayrı bir işlemciye programlanabileceğinden (ancak zorunlu olarak gerekmediğinden), çok işlemcili bir makinede birden çok iş parçacığı paralel olarak çalışabilir.

Tek işlemcili bir makinede, iş parçacıkları hızlı bir şekilde zaman dilimlenir ve önlenir (aralarında değiştirilir) (Linux'ta varsayılan zaman dilimi 100ms'dir), bu da onları eşzamanlı hale getirir. Ancak, tek çekirdekli işlemci aynı anda yalnızca bir şeyi çalıştırabildiğinden, paralel olarak (aynı anda) çalıştırılamazlar.

Ortak programlar ve / veya jeneratörler , işbirliği işlevlerini yerine getirmek için kullanılabilir. Çekirdek iş parçacıkları üzerinde çalıştırılmak ve işletim sistemi tarafından zamanlanmak yerine, programcı tarafından belirlenen diğer işlevlere ulaşarak, verim veya bitene kadar tek bir iş parçacığında çalışırlar. İle Diller jeneratörler , Python ve ECMAScript'e 6 gibi, coroutines oluşturmak için kullanılabilir. Async / await (C #, Python, ECMAscript 7, Rust'da görülüyor), gelecekleri / vaatleri veren jeneratör işlevlerinin üzerine inşa edilmiş bir soyutlamadır.

Bazı bağlamlarda, yardımcı programlar istifleyici işlevlere işaret ederken, üreteçler istifsiz işlevlere işaret edebilir.

Lifler , hafif iplikler ve yeşil iplikler , coroutines veya coroutine benzeri şeyler için diğer adlardır. Bazen (tipik olarak bilerek) programlama dilinde işletim sistemi iş parçacıklarına benzeyebilirler, ancak gerçek iş parçacıkları gibi paralel çalışmazlar ve bunun yerine koroutinler gibi çalışırlar. (Dile veya uygulamaya bağlı olarak bu kavramlar arasında daha spesifik teknik özellikler veya farklılıklar olabilir.)

Örneğin, Java'nın " yeşil konuları " vardı ; bunlar, temel işletim sisteminin çekirdek iş parçacığı yerine yerel olarak Java sanal makinesi (JVM) tarafından zamanlanan iş parçacıklarıydı. Bunlar paralel olarak çalışmadı veya birden fazla işlemci / çekirdekten faydalanmadı - çünkü bu yerel bir iş parçacığı gerektiriyordu! İşletim sistemi tarafından planlanmadığından, çekirdek iş parçacıklarından ziyade koroutinlere benziyorlardı. Yeşil iş parçacıkları, yerel iş parçacıkları Java 1.2 ile tanıştırılana kadar Java'nın kullandığı şeydir.

Konular kaynakları tüketir. JVM'de, her iş parçacığının kendi yığını vardır, genellikle 1 MB boyutunda. 64k, JVM'de iş parçacığı başına izin verilen en az yığın alanıdır. İş parçacığı yığın boyutu JVM için komut satırında yapılandırılabilir. Adına rağmen, iş parçacıkları kendi yığınına ihtiyaç duyan her iş parçacığı, varsa iş parçacığı yerel depolaması (varsa) ve iş parçacığı zamanlama / bağlam değiştirme / CPU önbellek geçersiz kılma maliyeti nedeniyle iş parçacığı ücretsiz değildir. Bu, yardımcı programların performans açısından kritik, yüksek eşzamanlı uygulamalar için popüler hale gelmesinin nedenlerinden biridir.

Mac OS yalnızca bir işlemin yaklaşık 2000 iş parçacığı ayırmasına izin verir ve Linux her iş parçacığı başına 8 MB yığın ayırır ve yalnızca fiziksel RAM'e sığacak sayıda iş parçacığına izin verir.

Bu nedenle, iş parçacıkları en ağır ağırlıktır (bellek kullanımı ve bağlam değiştirme süresi açısından), daha sonra koroutinler ve son olarak jeneratörler en hafif ağırlıktır.


2
+1, ancak bu yanıt bazı referanslardan yararlanabilir.
kojiro

1
Yeşil iplikler, koroutinlerden farklı bir şeydir. değil mi? Liflerin bile bazı farklılıkları vardır. bkz. programmers.stackexchange.com/questions/254140/…

113

Yaklaşık 7 yıl geç kaldı, ancak buradaki yanıtlarda eş-rutinler ve iş parçacıkları hakkında bazı bağlamlar eksik. Neden eşyordamlar son zamanlarda çok fazla dikkat çekmeye ve ben kıyasla bunları yaparken kullanacağı iş parçacığı ?

Her şeyden önce, eşbütünler eşzamanlı olarak çalışırsa (asla paralel değil ), neden bunları iş parçacıkları yerine tercih edesiniz ?

Cevap, coroutines'in çok az ek yük ile çok yüksek bir eşzamanlılık düzeyi sağlayabilmesidir . Genellikle dişli bir ortamda, genel olarak harcanan miktardan önce en fazla 30-50 iş parçacığına sahipsiniz, bu iş parçacıklarını (sistem zamanlayıcı tarafından) zamanlamak iş parçacıklarının gerçekten işe yaradığı süreyi önemli ölçüde azaltır.

Tamam, iş parçacıkları ile paralellik olabilir, ama çok fazla paralellik olabilir, bu hala tek bir iş parçacığında çalışan bir rutin daha iyi değil mi? Her zaman değil. Bir eş programın zamanlayıcı yükü olmadan eşzamanlılık yapabileceğini unutmayın - sadece içerik anahtarlamanın kendisini yönetir.

Örneğin, bazı işler yapan bir rutininiz varsa ve bir süre çalışacağını bildiğiniz bir işlem gerçekleştirirse (yani bir ağ isteği), bir rutinle, sistem zamanlayıcısını ekleyerek ek bir rutine hemen geçebilirsiniz. bu karar - evet programcı gerekir eş rutinleri geçiş yapabilirsiniz zaman belirtin.

Çok sayıda çalışma yaparken ve gönüllü olarak birbirleri arasında geçiş yapan birçok rutinle, hiçbir programlayıcının ulaşmayı ummadığı bir verimlilik seviyesine ulaştınız. Artık onlarca iş parçacığının aksine birlikte çalışan binlerce coroutine sahip olabilirsiniz.

Rutinleriniz artık önceden belirlenmiş noktalar arasında geçiş yaptığından, artık paylaşılan veri yapılarını kilitlemekten de kaçınabilirsiniz (çünkü kodunuza hiçbir zaman kritik bir bölümün ortasında başka bir programa geçmesini söylemezsiniz)

Başka bir faydası, çok daha düşük bellek kullanımıdır. İş parçacığı modeli ile, her iş parçacığının kendi yığınını ayırması gerekir ve böylece bellek kullanımınız sahip olduğunuz iş parçacığı sayısı ile doğrusal olarak artar. Ko-rutinlerde, sahip olduğunuz rutin sayısının hafıza kullanımınızla doğrudan bir ilişkisi yoktur.

Ve son olarak, eş-rutinler çok dikkat çekiyor çünkü bazı programlama dillerinde (Python gibi) iş parçacıklarınız yine de paralel olarak çalışamaz - eş zamanlı olarak koroinler gibi çalışırlar, ancak düşük bellek ve ücretsiz zamanlama yükü olmadan.


2
Bir engelleme işlemiyle karşılaştığımızda, programlarda başka bir göreve nasıl geçilir?
Narcisse Doudieu Siewe

Başka bir göreve geçme şekliniz, herhangi bir engelleme işleminin asenkron olarak gerçekleştirilmesidir. Bu, gerçekten engellenecek herhangi bir işlemi kullanmaktan kaçınmanız ve yalnızca coroutine sisteminizde kullanıldığında engellememeyi destekleyen işlemleri kullanmanız gerektiği anlamına gelir. Bunun tek yolu, örneğin Windows'ta UMS gibi çekirdeğin desteklediği ortak programlara sahip olmaktır; burada UMS "iş parçacığı" bir sistem çağrısında her blokladığında zamanlayıcıya atlar.
retep998

@MartinKonecny ​​En son C ++ Threads TS, bahsettiğiniz yaklaşıma bağlı mı?
Nikos

Sonuçta modern bir programlama dili, hız kazanmak için birçok çekirdekteki CPU yoğun işlemlerini paralel hale getirmek için örneğin IO ve Threads gibi hesaplamalı olmayan ağır işlemler için tek bir CPU çekirdeğini verimli bir şekilde kullanmak için her iki Coroutines / Fiber'e ihtiyaç duyacaktır, değil mi?
Mahatma_Fatal_Error

19

Tek kelimeyle: önleme. Coroutines, birbirlerine iyi prova edilmiş puanlar vermeye devam eden hokkabazlar gibi davranır. Dişler (gerçek dişler) hemen hemen her noktada kesilebilir ve daha sonra devam ettirilebilir. Tabii ki, bu her türlü kaynak çatışması sorununu beraberinde getiriyor, dolayısıyla Python'un meşhur GIL - Global Tercüman Kilidi.

Birçok iş parçacığı uygulaması aslında daha çok koroutinlere benzer.


9

Kullandığınız dile bağlıdır. Örneğin Lua'da aynı şeydir (bir koroutinin değişken tipine denir thread).

Genellikle yardımcı programlar, programcı (siz) yieldbaşka bir rutini nerede kontrol edeceğinize (yani ) karar verdiğiniz yerde gönüllü verim uygular .

Bunun yerine iplikler işletim sistemi tarafından otomatik olarak yönetilir (durdurulur ve başlatılır) ve hatta çok çekirdekli işlemcilerde aynı anda çalışabilirler.


0

Tartışmaya 12 yıl geç kaldı ama adında bir coroutine açıklama var. Koroutin, Co ve Rutine'ye ayrılabilir.

Bu bağlamdaki bir rutin sadece bir işlem / eylem dizisidir ve bir rutinin yürütülmesi / işlenmesi ile işlem dizisi, belirtilenle aynı sırayla tek tek yürütülür.

Co işbirliği anlamına gelir. Bir eş rutinden, diğer eş rutinlere de yürütme şansı vermek için yürütmeyi isteyerek askıya alması istenir (ya da daha iyisi beklenir). Yani bir rutin, CPU kaynaklarını (isteyerek) paylaşmakla ilgilidir, böylece diğerleri kendi kullandığı kaynakla aynı kaynağı kullanabilir.

Öte yandan bir iş parçacığının yürütülmesini askıya alması gerekmez. Askıda olmak, dişe tamamen şeffaftır ve iplik, altta yatan donanım tarafından kendini askıya almaya zorlanır. Ayrıca, bildirim alınmadığı ve iş parçacığının devam etmesine izin verildiğinde durumu değiştirilmedi, kaydedilip daha sonra geri yüklendiği için çoğunlukla iş parçacığına şeffaf olacak şekilde yapılır.

Doğru olmayan bir şey, eş-rutinlerin eşzamanlı olarak yürütülemeyeceği ve yarış koşullarının meydana gelemeyeceği. Ko-rutinlerin çalıştığı sisteme bağlıdır ve ko-rutinleri görüntülemek kolaydır.

Ko-rutinlerin kendilerini nasıl askıya aldıkları önemli değildir. Geri Windows 3.1 int 03 herhangi bir programa dokunmuş (veya oraya yerleştirilmesi gerekiyordu) ve C # biz verim eklemek.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.