İş parçacığı kod yürütülmesini hızlandırabilir, ancak gerçekten gerekli mi? Her kod parçası tek bir iş parçacığı kullanılarak yapılabilir mi, yoksa yalnızca birden çok iş parçacığı kullanılarak gerçekleştirilebilecek bir şey var mı?
İş parçacığı kod yürütülmesini hızlandırabilir, ancak gerçekten gerekli mi? Her kod parçası tek bir iş parçacığı kullanılarak yapılabilir mi, yoksa yalnızca birden çok iş parçacığı kullanılarak gerçekleştirilebilecek bir şey var mı?
Yanıtlar:
Her şeyden önce, iş parçacığı kod yürütülmesini hızlandıramaz. Bilgisayarı daha hızlı çalıştırmazlar. Tek yapabilecekleri boşa harcanacak zamanı kullanarak bilgisayarın verimliliğini artırmak. Bazı işlem türlerinde bu optimizasyon verimliliği artırabilir ve çalışma süresini kısaltabilir.
Basit cevap evet. Tek bir iş parçacığında çalıştırılacak herhangi bir kod yazabilirsiniz. İspat: Tek bir işlemci sistemi talimatları yalnızca doğrusal çalıştırabilir. Birden fazla uygulama satırına sahip olmak, işletim sisteminin işlem kesintileri, mevcut iş parçacığının durumunu kaydetme ve bir başkasının başlatılması ile yapılır.
Karmaşık cevap daha karmaşık ... olduğunu! Çok iş parçacıklı programların genellikle doğrusal programlardan daha verimli olmasının nedeni, bir donanım "sorunu" nedeniyledir. CPU hesaplamaları hafızadan ve sabit depolama IO'sundan daha hızlı gerçekleştirebilir. Dolayısıyla, bir "add" komutu, örneğin, bir "getir" den çok daha hızlı bir şekilde yürütülür. Önbellek ve özel program komutunun getirilmesi (buradaki terimin tam olduğundan emin değilsiniz), bununla bir dereceye kadar savaşabilir, ancak hız sorunu devam etmektedir.
Diş açma, IO talimatları tamamlanırken CPU'ya bağlı talimatlar için CPU kullanarak bu uyumsuzlukla mücadelenin bir yoludur. Tipik bir iş parçacığı yürütme planı muhtemelen olacaktır: Veri alma, veri işleme, veri yazma. Alma ve yazma işleminin 3 döngü sürdüğünü ve işlemenin açıklama amacıyla alındığını varsayalım. Bilgisayarın okurken veya yazarken, her biri 2 döngü için hiçbir şey yapmadığını görebiliyor musunuz? Açıkçası tembel olmak ve optimizasyon kırbaçımızı kırmamız gerek!
Bu boşa harcanan zamanı kullanmak için iş parçacığı kullanarak işlemi yeniden yazabiliriz:
Ve bunun gibi. Açıkçası bu biraz tartışmalı bir örnek, ancak bu tekniğin aksi halde IO için harcanacak zamanı nasıl kullanabileceğini görebilirsiniz.
Yukarıda gösterildiği gibi diş açmanın yalnızca yoğun GÇ bağlantılı işlemlerde verimliliği artırabileceğini unutmayın. Eğer bir program esas olarak bir şeyler hesaplıyorsa, daha fazla çalışabileceğimiz çok fazla "delik" olmayacak. Ayrıca, dişler arasında geçiş yaparken birkaç talimatın da bir üst kısmı olacak. Çok fazla iş parçacığı çalıştırırsanız, işlemci zaman değiştirmeye harcayacak ve aslında sorun üzerinde çalışmayacak. Buna devrilme denir .
Hepsi tek bir çekirdekli işlemci için iyidir ve iyidir, ancak çoğu modern işlemcinin iki veya daha fazla çekirdeği vardır. İplikler hala aynı amaca hizmet ediyor - CPU kullanımını en üst düzeye çıkarmak, ancak bu sefer aynı anda iki ayrı komut çalıştırabiliyoruz . Bu , çalışma süresini bir çok çekirdeğin etkisiyle azaltabilir, çünkü bilgisayar aslında bağlam değiştirmeyi değil, çok görevlidir.
Çoklu çekirdeklerde dişler, iki çekirdek arasında işi bölme yöntemi sağlar. Yukarıdakiler yine de her bir çekirdek için hala geçerlidir; Bir çekirdekte iki diş ile maksimum verim sağlayan bir program büyük olasılıkla iki çekirdekte yaklaşık dört diş ile zirve verimde çalışacaktır. (Burada verimlilik, minimum NOP talimatı yürütmeleri ile ölçülür.)
Çoklu çekirdeklerde (tek bir çekirdeğin aksine) akan ipliklerle ilgili problemler genellikle donanım ile halledilir. CPU, okumadan / yazmadan önce uygun bellek konumlarını kilitlediğinden emin olacaktır. (Bunun için bellekte özel bir bayrak ucu kullandığını okudum, ancak bu birkaç yolla başarılabilir.) Yüksek seviyeli dilleri olan bir programcı olarak, iki çekirdekten daha fazla bir şey için endişelenmenize gerek yok biriyle yapmak zorunda kalacaktı.
TL; DR: İşler, bilgisayarın birkaç görevi zaman uyumsuz olarak işlemesini sağlamak için işleri bölebilir. Bu, bir işlem bir kaynağı beklerken kilitlemek yerine, mevcut tüm işlem sürelerini kullanarak bilgisayarın maksimum verimlilikte çalışmasını sağlar.
Birden fazla iş parçacığı tek bir iş parçacığının yapamadığı ne yapabilir?
Hiçbir şey değil.
Basit kanıtı kroki:
Orada gizlenmiş büyük bir varsayım olduğunu, ancak, Not: Kullanılan dil yani o içindeki tek iplik Turing-tamamlandı.
Öyleyse, daha ilginç olan soru şuydu: " Turing'in tamamlanmadığı bir dile sadece çoklu iş parçacığı eklenmesi Turing'i tamamlayabilir mi?" Ve inanıyorum ki, cevap "Evet".
Toplam Fonksiyonel Dilleri alalım. [Bilinmeyenler için: Fonksiyonel Programlamanın Fonksiyonlarla Programlama Yapması gibi, Fonksiyonel Programlamanın Toplam Fonksiyonlarla Programlanması gibi.]
Toplam Fonksiyonel Diller açıkçası Turing tamamlama değildir: Bir TfpL sonsuz bir döngüye yazamaz (aslında, bu oldukça fazla olduğunu tanımı "toplam" nin), ancak yapabilirsiniz bir Turing Machine, ergo orada en az bir programı var olduğunu Bir TFPL’de yazılamaz ancak bir UTM’de yazılabilir, bu nedenle TFPL’ler UTM’lerden daha az hesaplamalı olarak güçlüdür.
Bununla birlikte, bir TFPL'ye iş parçacığı eklediğiniz anda sonsuz döngüler elde edersiniz: Yeni bir iş parçacığı içinde döngü her yinelemesini yapın. Her bir iş parçacığı her zaman bir sonuç döndürür, bu nedenle Toplam'dır, ancak her iş parçacığı bir sonraki yinelemeyi ve infinitum'u uygulayan yeni bir iş parçacığı açar.
Ben düşünüyorum bu dil Turing-tam olacağını.
En azından, orijinal soruyu yanıtlıyor:
Birden fazla iş parçacığı tek bir iş parçacığının yapamadığı ne yapabilir?
Eğer sonsuz döngüler yapamaz bir dili var, o zaman çoklu iş parçacığı sonsuz döngü yapmak için izin verir.
Elbette, bir ipliğin ortaya çıkmasının bir yan etki olduğunu ve bu nedenle genişletilmiş dilin artık sadece Toplam olmadığını, artık İşlevsel olmadığını da unutmayın.
Teoride, çok iş parçacıklı bir programın yaptığı her şey tek bir iş parçacıklı programla da yapılabilir, ancak daha yavaştır.
Uygulamada, hız farkı o kadar büyük olabilir ki, görev için tek iş parçacıklı bir program kullanmanın bir yolu yoktur. Örneğin, her gece çalışan bir toplu veri işleme işiniz varsa ve tek bir iş parçacığında bitirmek 24 saatten fazla sürerse, çok iş parçacıklı hale getirmekten başka seçeneğiniz yoktur. (Uygulamada, eşik muhtemelen daha da azdır: sık sık bu güncelleme görevleri, kullanıcılar sistemi tekrar kullanmaya başlamadan önce sabahın erken saatlerinde bitmelidir. Ayrıca, diğer görevler de aynı gece boyunca bitmesi gereken bunlara bağlı olabilir. kullanılabilir çalışma zamanı birkaç saat / dakika kadar düşük olabilir.)
Bilişim işi birden çok iş parçacığı üzerinde yapmak, dağıtılmış işlem biçimidir; çalışmayı birden fazla iş parçacığı üzerine dağıtıyorsunuz. Dağıtılmış işlemlere başka bir örnek (birden fazla iş parçacığı yerine birden fazla bilgisayar kullanarak) SETI ekran koruyucusudur: tek bir işlemcide bu kadar fazla ölçüm verisinin çok uzun zaman alacağını ve araştırmacıların emeklilikten önce sonuçları görmeyi tercih ettiklerini; Uzun süredir bir süper bilgisayar kiralamak için bütçeniz yok, bu yüzden işi ucuz hale getirmek için milyonlarca ev bilgisayarına dağıtıyorlar.
İplikler sıralı hesaplamadan küçük bir adım gibi görünmekle birlikte, aslında büyük bir adımı temsil eder. Sıralı hesaplamanın en temel ve çekici özelliklerini atarlar: anlaşılabilirlik, öngörülebilirlik ve determinizm. Bir hesaplama modeli olarak konu başlıkları çılgınca belirsizdir ve programcının işi bu belirtisizliğin budamasıdır.
- Konularla İlgili Sorun (www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf).
İşleri birden fazla çekirdeğe dağıtabilmeniz için iplikler kullanarak elde edilebilecek bazı performans avantajları olsa da, genellikle büyük bir fiyata gelir.
Henüz burada bahsedilmeyen dişleri kullanmanın olumsuz yanlarından biri, tek dişli işlem alanları ile elde ettiğiniz kaynak bölümlendirme kaybıdır. Örneğin, bir segfault davasıyla karşılaştığınızı söyleyin. Bazı durumlarda, bundan dolayı suçlu çocuğun ölmesine ve yeni bir tane yeniden doğmasına izin vermeniz için çok işlemli bir uygulamada iyileşmek mümkündür. Bu, Apache'nin prefork arka ucundaki durumdur. Bir httpd örneği ortaya çıktığında, en kötü durum, söz konusu işlem için belirli HTTP isteğinin bırakılabileceği, ancak Apache'nin yeni bir çocuk ortaya çıkardığı ve genellikle yeniden gönderilip servis verildiği takdirde isteğin ortaya çıktığıdır. Sonuçta, Apache bir bütün olarak hatalı iş parçacığı ile alınmaz.
Bu senaryoda bir diğer husus, bellek sızıntısıdır. Bir iş parçacığı çökmesini dikkatlice idare edebileceğiniz bazı durumlar vardır (UNIX'de, belirli sinyallerden kurtarma - hatta segfault / fpviolation bile mümkündür), ancak bu durumda bile, bu iş parçacığı tarafından ayrılan tüm belleği sızdırmış olabilirsiniz (malloc, yeni, vb). Bu nedenle işlem devam ederken, her hata / düzelme ile zamanla daha fazla bellek sızdırıyor. Yine, Apache'nin bellek havuzlarını kullanması gibi, bunu en aza indirmenin bir dereceye kadar yolu vardır. Ancak bu hala, iş parçacığının kullanmış olabileceği üçüncü taraf liblerin tahsis ettiği hafızaya karşı korunmuyor.
Bazı insanların da belirttiği gibi, senkronizasyon ilkellerini anlamak belki de gerçekten doğru olan en zor şeydir. Kendi başına bu sorun - sadece tüm kodunuz için genel mantığı bulmak - çok büyük bir baş ağrısı olabilir. Gizemli çıkma kilitleri en tuhaf zamanlarda, bazen de programınız üretimde çalışana kadar gerçekleşmeyebilir, bu da hata ayıklamayı daha da zorlaştırır. Buna ek olarak, senkronizasyon ilkellerinin çoğu platforma (Windows ve POSIX) göre büyük ölçüde değiştiği ve hata ayıklamanın daha zor olabileceği gibi, herhangi bir zamanda yarış koşulları olasılığını (başlatma / başlatma, çalışma zamanı ve kapatma), iş parçacığı ile programlama gerçekten yeni başlayanlar için çok az merhamet vardır. Ve hatta uzmanlar için orada hala küçük bir merhamet var, çünkü diş açma bilgisi genel olarak karmaşıklığı en aza indirmiyor. Her bir iş parçacığı kodu satırı, katlanarak programın genel karmaşıklığını birleştirir ve aynı zamanda gizli bir kilitlenme ya da garip yarış koşulunun herhangi bir zamanda yüzeye çıkma olasılığını arttırır. Bunları ortadan kaldırmak için test senaryoları yazmak da çok zor olabilir.
Bu nedenle Apache ve PostgreSQL gibi bazı projeler çoğu zaman süreç tabanlı. PostgreSQL, her arka uç iş parçacığını ayrı bir işlemde çalıştırır. Elbette bu hala senkronizasyon ve yarış koşullarını hafifletmiyor, ancak oldukça fazla koruma sağlıyor ve bazı şeyleri basitleştiriyor.
Her biri tek bir yürütme iş parçacığı çalıştıran birden çok işlem, tek bir işlemde çalışan birden çok iş parçacığından çok daha iyi olabilir. AMQP (RabbitMQ, Qpid, vb.) Ve ZeroMQ gibi eşler arası yeni kodların çoğunun ortaya çıkmasıyla, farklı işlem alanlarına ve hatta makinelere ve ağlara dişleri ayırmak, işleri büyük ölçüde basitleştirerek çok daha kolaydır. Ama yine de, gümüş bir mermi değil. Başa çıkmak için hala bir karmaşıklık var. Değişkenlerinizden bazılarını işlem alanından ağa taşımanız yeterlidir.
Sonuç olarak, iplik alanına girme kararı hafif değildir. Bir kez o bölgeye ayak bastığınızda, neredeyse anında her şey daha karmaşık hale gelir ve yepyeni sorun ırkları hayatınıza girer. Eğlenceli ve havalı olabilir, ama nükleer güç gibi - işler ters gittiğinde kötü ve hızlı gidebilirler. Uzun yıllar önce kritiklik eğitimi alan bir sınıf aldığımı hatırlıyorum ve Los Alamos'ta, II. Dünya Savaşı'ndaki laboratuvarlarında plütonyum ile oynayan bazı bilim adamlarının resimlerini gösterdiklerini hatırlıyorum. Birçoğu maruz kalma olayına karşı çok az önlem aldı veya hiç bir önlem almadı ve göz açıp kapayıncaya kadar - tek bir parlak, ağrısız flaşta, hepsi onlar için bitecekti. Günler sonra öldüler. Richard Feynman daha sonra buna " ejderhanın kuyruğunu gıdıklıyor " dedi.“Bu, ipliklerle oynamanın nasıl bir şey olduğunu (en azından zaten benim için). İlk başta oldukça zararsız gözüküyor ve ısırılınca, başınızın işlerin ne kadar çabuk düştüğünü kafanızı çiziyorsunuz. Seni öldürme
Birincisi, tek bir dişli uygulama hiçbir zaman çok çekirdekli bir işlemciden veya aşırı iş parçacıklığından asla yararlanamayacaktır. Ancak, tek bir çekirdekte bile, çoklu iş parçacığı yapan tek iş parçacıklı CPU'nun avantajları vardır.
Alternatifleri ve bunun sizi mutlu edip etmediğini düşünün. Aynı anda çalışması gereken birden fazla göreviniz olduğunu varsayalım. Örneğin, iki farklı sistemle iletişiminizi sürdürmek zorundasınız. Çok iş parçacıklı olmadan bunu nasıl yapıyorsun? Muhtemelen kendi zamanlayıcınızı yaratır ve gerçekleştirilmesi gereken farklı görevleri çağırmasına izin verirsiniz. Bu, görevlerinizi parçalara ayırmanız gerektiği anlamına gelir. Muhtemelen parçalarınızın çok fazla zaman almadığından emin olmanız gereken bazı gerçek zamanlı kısıtlamaları yerine getirmeniz gerekir. Aksi halde, zamanlayıcı diğer görevlerde sona erer. Bu, görevi bölmeyi daha da zorlaştırır. Kendinizi yönetmek için ne kadar çok görev yapmanız gerekiyorsa, ne kadar bölünmüş olursanız ve zamanlamanız o kadar karmaşıklaşır ve tüm kısıtlamaları yerine getirebilir.
Birden fazla dişiniz olduğunda, hayat daha kolay olabilir. Önleyici bir zamanlayıcı, bir iş parçacığını istediği zaman durdurabilir, durumunu koruyabilir ve başka birini başlatabilir. İplik sırası geldiğinde yeniden başlatılır. Avantajları: bir zamanlayıcı yazma karmaşıklığı zaten sizin için yapıldı ve görevlerinizi bölmek zorunda değilsiniz. Ayrıca, zamanlayıcı kendinizin bile bilmediğiniz işlemleri / konuları yönetme yeteneğine sahiptir. Ayrıca, bir iş parçacığının herhangi bir şey yapması gerekmediğinde (bazı olayları bekliyor) CPU çevrimi gerektirmez. Aşağı iş parçacıklı zamanlayıcı oluştururken, bu başarmak kolay değil. (bir şeyi uykuya koymak çok zor değildir, ama nasıl uyanır?)
Çok iş parçacıklı gelişimin dezavantajı, eşzamanlılık sorunları, kilitleme stratejileri vb. Hakkında anlamanız gerektiğidir. Hatasız çoklu iş parçacıklı kod geliştirme oldukça zor olabilir. Ve hata ayıklama daha da zor olabilir.
sadece birden fazla iş parçacığı kullanılarak gerçekleştirilebilecek bir şey var mı?
Evet. Tek bir iş parçacığı ile birden fazla CPU'da veya CPU çekirdeğinde kod çalıştıramazsınız.
Birden fazla CPU / çekirdek olmadan, iş parçacığı hala bir sunucudaki istemci işleme gibi kavramsal olarak paralel çalışan kodu basitleştirebilir - ancak aynı şeyi iş parçacığı olmadan da yapabilirsiniz.
Konular sadece hız ile ilgili değil, eşzamanlılıkla da ilgilidir.
@Peter'in önerdiği bir toplu iş uygulamanız yoksa bunun yerine WPF gibi bir GUI araç takımı yoksa kullanıcılar ve iş mantığı ile tek bir iş parçacığı ile nasıl etkileşime girersiniz?
Ayrıca, bir Web Sunucusu kurduğunuzu varsayalım. Birden fazla kullanıcıya eşzamanlı olarak tek bir iş parçacığıyla nasıl hizmet edersiniz (başka işlem olmadığını varsayarak)?
Sadece basit bir iş parçacığının yeterli olmadığı birçok senaryo var. Bu yüzden 50'den fazla çekirdeğe ve yüzlerce iş parçacığına sahip Intel MIC işlemci gibi yeni gelişmeler yaşanıyor.
Evet, paralel ve eşzamanlı programlama zordur. Fakat gerekli.
Multi-Threading, GUI arayüzünün uzun işleme işlemleri sırasında hala duyarlı olmasına izin verebilir. Çok iş parçacığı olmadan, uzun bir işlem çalışırken kullanıcı kilitli bir formu izlemekte sıkışıp kalır.
Çok iş parçacıklı kod, program mantığını kilitleyebilir ve eski iş verilerine tek iş parçacığının yapamadığı şekillerde erişebilir.
İş parçacığı, ortalama bir programcının hata ayıklaması ve bir uyarıcı programcının tam olarak bakması durumunda, aynı hatayı yakalamak için gerekli şanstan bahseden hikayelerin söylendiği bölgeye düşmesi ve tahmin edilebileceği bir bölgeden gizli bir hata alabilir. doğru an.
Diğer girişlere (GUI veya diğer bağlantılar) karşı da duyarlı olması gereken IO'yu engelleme ile ilgili uygulamalar tek başlarına yapılamaz
engellemeden ne kadar okunabileceğini görmek için IO kütüphanesine denetim yöntemlerinin eklenmesi buna yardımcı olabilir, ancak pek çok kütüphane bu konuda tam bir garanti vermez.
Çok iyi cevaplar var ama tam olarak söylediğimden emin değilim - Belki de bu ona bakmak için farklı bir yol sunar:
Konular sadece Nesneler veya Aktörler gibi veya döngüler için bir programlama basitleştirmesidir (Evet, if / goto ile uygulayabileceğiniz döngüler ile uyguladığınız her şey).
Konu olmadan basitçe bir durum motoru uygularsınız. Bunu birçok kez yapmak zorunda kaldım (İlk kez yaptığımda hiç duymamıştım - sadece bir "Devlet" değişkeni tarafından kontrol edilen büyük bir anahtar ifadesi yaptı). Devlet makineleri hala oldukça yaygın ancak can sıkıcı olabilir. İplerle, kazan plakasının büyük bir bölümü kaybolur.
Ayrıca, bir dilin çalışma zamanı çalışmasını çoklu CPU dostu parçalara bölmesini kolaylaştırıyorlar (Öyleyse Oyuncular, inanıyorum).
Java, işletim sisteminin HERHANGİ bir iş parçacığı desteği sağlamadığı sistemlerde "Yeşil" iş parçacıkları sağlar. Bu durumda açıkça bir programlama soyutlamasından başka bir şey olmadığını görmek daha kolaydır.
OS'ler, her iş parçacığının çalışma zamanının geldiği ve ardından önlendiği zaman dilimleme konseptini kullanır. Bunun gibi bir yaklaşım şu anda olduğu gibi diş açmanın yerini alabilir, ancak her uygulamada kendi zamanlayıcılarınızı yazmanız önemsizdir. Üstelik, G / Ç aygıtları ve benzerleriyle çalışmak zorundasınız. Ve donanım bölümünden biraz destek almanız gerekir, böylece zamanlayıcınızın çalışmasını sağlamak için kesintileri yapabilirsiniz. Temelde her zaman yeni bir işletim sistemi yazıyor olacaksınız.
Genel olarak diş açma, dişlilerin G / Ç için beklediği veya uyuduğu durumlarda performansı artırabilir. Ayrıca, uzun görevleri yerine getirirken, duyarlı arabirimler oluşturmanıza ve durma işlemlerine izin vermenize de olanak tanır. Ayrıca, iş parçacığı gerçek çok çekirdekli işlemcilerde işleri geliştirir.
İlk olarak, iş parçacığı aynı anda iki veya daha fazla şey yapabilir (birden fazla çekirdeğiniz varsa). Bunu birden fazla işlemle de yapabilirsiniz, ancak bazı görevler yalnızca birden fazla işlemin üzerine çok iyi dağılmaz.
Ayrıca, bazı görevlerde kolayca önleyemeyeceğiniz boşluklar vardır. Örneğin, diskteki bir dosyadan veri okumak ve işleminizin aynı anda başka bir şey yapmasını sağlamak zordur. Göreviniz mutlaka diskten çok fazla okuma verisi gerektiriyorsa, işleminiz ne yaparsanız yapın diski beklemek için çok zaman harcayacaktır.
İkinci olarak, iş parçacıkları, performansınız için kritik olmayan kodunuzun büyük miktarlarını optimize etmek zorunda kalmamanıza izin verebilir. Yalnızca tek bir iş parçacığınız varsa, her kod parçası performans açısından önemlidir. Engellenirse, batırılırsınız - bu işlem tarafından yapılacak hiçbir iş ilerlememizi sağlayamaz. İş parçacığı ile bir blok sadece iş parçacığı ve diğer iş parçacıklarının ortaya çıkmasını ve bu işlem tarafından yapılması gereken işleri yapmasını etkiler.
İyi bir örnek, nadiren yürütülen hata işleme kodudur. Bir görevin çok nadir görülen bir hatayla karşılaştığını ve bu hatayı gidermek için gereken kodun belleğe girmesi gerektiğini söyleyin. Disk meşgulse ve işlem yalnızca tek bir iş parçacığına sahipse, bu hatayı işlemek için kod belleğe yüklenene kadar herhangi bir ilerleme kaydedilmez. Bu, patlayıcı tepkiye neden olabilir.
Başka bir örnek ise, nadiren bir veritabanı araması yapmanız gerekebilir. Veritabanının cevap vermesini beklerseniz, kodunuz çok büyük bir gecikmeye neden olur. Ancak tüm bu kodu senkronize etme zahmetine girmek istemiyorsunuz çünkü bu aramaları yapmanız çok nadirdir. Bu işi yapmak için bir iplik ile, her iki dünyanın da en iyisini elde edersiniz. Bu işi yapmak için bir iş parçacığı olması gerektiği gibi performans kritik değildir.