“CPU bağlı” ve “I / O bağlı” terimleri ne anlama geliyor?


Yanıtlar:


452

Oldukça sezgisel:

Bir program, CPU daha hızlı olsaydı daha hızlı giderse CPU'ya bağlıdır, yani zamanının çoğunu sadece CPU kullanarak harcıyor (hesaplamalar yapıyor). Yeni its rakamlarını hesaplayan bir program tipik olarak CPU'ya bağlı olacaktır, sadece sayıları eziyor.

Bir program, G / Ç alt sistemi daha hızlı olsaydı daha hızlı giderse G / Ç'ye bağlıdır. Hangi kesin G / Ç sisteminin kastedildiği değişebilir; Genellikle diskle ilişkilendiririm, ancak elbette ağ veya genel olarak iletişim de yaygındır. Bazı veriler için büyük bir dosyaya bakan bir program G / Ç'ye bağlı olabilir, çünkü darboğaz o zaman diskten verilerin okunmasıdır (aslında, bu örnek belki de bugünlerde yüzlerce MB / s ile eski moda bir çeşittir) SSD'lerden geliyor).


Bu, bir mobil cihazdaki HTTP iletişimini anlama ile nasıl bağlantılıdır? Java.nio işlemlerini kullanarak CPU kullanımında artış olduğunu gördüm .
IgorGanapolsky

G / Ç "giriş / çıkış" tır.
Yoldaş Che

247

CPU Bound , işlemin ilerleme hızı CPU hızı ile sınırlı olduğu anlamına gelir. Küçük sayı kümelerinde hesaplamalar yapan, örneğin küçük matrisleri çarpma gibi bir görevin CPU'ya bağlı olması muhtemeldir.

G / Ç Sınırı , bir işlemin ilerleme hızı G / Ç alt sisteminin hızı ile sınırlı olduğu anlamına gelir. Örneğin, bir dosyadaki satır sayısını saymak gibi verileri diskten işleyen bir görevin G / Ç'ye bağlı olması muhtemeldir.

Bellek bağlı , bir işlemin ilerleme hızı, kullanılabilir bellek miktarı ve bu belleğe erişim hızıyla sınırlıdır. Büyük miktarda bellek verisi işleyen, örneğin büyük matrisleri çarpma gibi bir görevin büyük olasılıkla Bellek Bağlı olması muhtemeldir.

Önbellek bağlı , bir işlem ilerlemesinin kullanılabilir önbellek miktarı ve hızı ile sınırlı olduğu anlamına gelir. Önbelleğe sığmayacak kadar çok veri işleyen bir görev önbelleğe bağlı olacaktır.

G / Ç Bağlama, Bellek Bağlama'dan Önbellek Bağlama işlemcisinden CPU Bağlantısı'na göre daha yavaş olacaktır.

G / Ç bağlı olmanın çözümü, daha fazla Bellek elde etmek zorunda değildir. Bazı durumlarda, erişim algoritması G / Ç, Bellek veya Önbellek sınırlamaları etrafında tasarlanabilir. Bkz. Önbellek Oblivious Algoritmaları .


73

Multi-Threading

Bu cevapta, CPU ile IO sınırlı iş arasında ayrım yapmak için önemli bir kullanım durumunu araştıracağım: çok iş parçacıklı kod yazarken.

RAM G / Ç bağlantılı örnek: Vektör Toplamı

Tek bir vektörün tüm değerlerini toplayan bir program düşünün:

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

Her bir çekirdeğiniz için diziyi eşit olarak bölerek, ortak modern masaüstlerinde sınırlı kullanışlılığa paraleldir.

Örneğin, Ubuntu 19.04, CPU'lu Lenovo ThinkPad P51 dizüstü bilgisayarımda: Intel Core i7-7820HQ CPU (4 çekirdek / 8 konu), RAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB) Şunun gibi sonuçlar alıyorum:

resim açıklamasını buraya girin

Verileri çizin .

Ancak çalışma arasında çok fazla varyans olduğunu unutmayın. Ama zaten 8GiB'de olduğum için dizi boyutunu daha fazla artıramıyorum ve bugün birden fazla çalışmadaki istatistikler için havamda değilim. Ancak bu, birçok manuel çalışma yaptıktan sonra tipik bir çalışma gibi görünüyordu.

Karşılaştırma kodu:

Eğrinin şeklini tam olarak açıklayacak kadar bilgisayar mimarisi bilmiyorum, ama bir şey açık: hesaplama, 8 parçamın hepsini kullandığım için safça beklendiği gibi 8 kat daha hızlı hale gelmiyor! Bazı nedenlerden dolayı, 2 ve 3 iş parçacıkları en uygun çözümdü ve daha fazlasını eklemek işleri daha yavaş hale getiriyor.

Bunu CPU'ya bağlı çalışma ile karşılaştırın, ki bu aslında 8 kat daha hızlıdır: 'Gerçek', 'kullanıcı' ve 'sys' zaman çıktısında ne anlama gelir (1)?

Tüm işlemcilerin RAM'e bağlanan tek bir bellek veri yolunu paylaşmasının nedeni:

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

böylece bellek veri yolu hızla CPU değil darboğaz haline gelir.

Bunun nedeni, iki sayı eklemenin tek bir CPU döngüsü gerektirmesi, bellek okumalarının 2016 donanımında yaklaşık 100 CPU döngüsü sürmesidir.

Bu nedenle, giriş verisi baytı başına yapılan CPU çalışması çok küçüktür ve buna IO'ya bağlı bir süreç diyoruz.

Bu hesaplamayı daha da hızlandırmanın tek yolu, bireysel bellek erişimini yeni bellek donanımıyla, örneğin Çok kanallı bellekle hızlandırmak olacaktır .

Örneğin daha hızlı bir CPU saatine yükseltmek çok yararlı olmaz.

Diğer örnekler

CPU veya IO bağlı olup olmadığınızı nasıl öğrenebilirsiniz?

RAM olmayan IO, disk, ağ: gibi bağlı ps aux, eğer CPU% / 100 < n threads. Evet ise, IO'ya bağlısınız, örneğin engelleme reads sadece veri bekliyor ve programlayıcı bu işlemi atlıyor. Ardından sudo iotop, hangi IO'nun sorun olduğuna tam olarak karar vermek gibi diğer araçları kullanın .

Ya da, yürütme hızlıysa ve iş parçacıklarının sayısını parametreleştirirseniz, timeCPU'ya bağlı iş için iş parçacığı sayısı arttıkça bunu iş performansının arttığından kolayca görebilirsiniz : 'Gerçek', 'kullanıcı' ve 'sys' ne anlama gelir? zamanın çıktısı (1)?

RAM-IO bağlı: söylemesi daha zor, RAM bekleme süresi CPU%ölçümlere dahil olduğundan , ayrıca bkz:

Bazı seçenekler:

GPU'lar

Giriş verilerini normal CPU tarafından okunabilen RAM'den GPU'ya ilk aktardığınızda GPU'larda bir GÇ darboğazı vardır.

Bu nedenle, GPU'lar yalnızca CPU bağlantılı uygulamalar için CPU'lardan daha iyi olabilir.

Ancak veriler GPU'ya aktarıldıktan sonra, bu baytlarda CPU'nun yapabileceğinden daha hızlı çalışabilir, çünkü GPU:

  • çoğu CPU sisteminden daha fazla veri yerelleştirmesine sahiptir ve bu nedenle bazı çekirdekler için verilere diğerlerinden daha hızlı erişilebilir

  • hemen kullanılmaya hazır olmayan herhangi bir verinin üzerinden atlayarak veri paralelliğinden yararlanır ve gecikmeyi feda eder.

    GPU'nun büyük paralel giriş verileri üzerinde çalışması gerektiğinden, geçerli verilerin kullanılabilir olmasını beklemek ve CPU'nun çoğunlukla yaptığı gibi diğer tüm işlemleri engellemek yerine, mevcut olabilecek bir sonraki veriye atlamak daha iyidir.

Bu nedenle, uygulamanız varsa GPU bir CPU'dan daha hızlı olabilir:

  • yüksek oranda paralelleştirilebilir: farklı veri parçaları aynı anda birbirinden ayrı olarak ele alınabilir
  • giriş baytı başına yeterli sayıda işlem gerektirir (örn. yalnızca bayt başına bir ekleme yapan vektör eklemenin aksine)
  • çok sayıda girdi baytı var

Bu tasarım seçenekleri, asıl adımları OpenGL'deki gölgelendiriciler nelerdir ve bunlara ne için ihtiyacımız var?

  • tepe gölgelendirici: 1x4 vektörün bir demetini 4x4 matrisiyle çarpma
  • fragman gölgelendirici: bir üçgenin her bir pikselinin rengini, üçgene sahip göreceli konumuna göre hesaplayın

ve böylece bu uygulamaların CPU'ya bağlı olduğu sonucuna varıyoruz.

Programlanabilir GPGPU'nun ortaya çıkmasıyla, CPU'ya bağlı işlemlere örnek olarak hizmet veren birkaç GPGPU uygulamasını gözlemleyebiliriz:

Ayrıca bakınız:

CPython Global Yorumlayıcı Kilidi (GIL)

Hızlı bir vaka çalışması olarak, Python Global Tercüman Kilidi'ne (GIL) dikkat çekmek istiyorum: CPython'daki küresel tercüman kilidi (GIL) nedir?

Bu CPython uygulama ayrıntısı, birden çok Python iş parçacığının CPU'ya bağlı işleri verimli bir şekilde kullanmasını engeller. CPython dokümanlar ki:

CPython uygulama ayrıntısı: CPython'da, Global Tercüman Kilidi nedeniyle, Python kodunu aynı anda yalnızca bir iş parçacığı yürütebilir (belirli performans odaklı kitaplıklar bu sınırlamanın üstesinden gelebilir). Uygulamanızın çok çekirdekli makinelerin hesaplama kaynaklarını daha iyi kullanmasını istiyorsanız multiprocessingveya seçeneğini kullanmanız önerilir concurrent.futures.ProcessPoolExecutor. Bununla birlikte, aynı anda birden fazla I / O bağlantılı görevi çalıştırmak istiyorsanız, iş parçacığı oluşturma yine de uygun bir modeldir.

Bu nedenle, burada CPU'ya bağlı içeriğin uygun olmadığı ve G / Ç sınırının uygun olduğu bir örneğimiz var.


1
Dostum, nasıl bu kadar yetkin olmayı ve böyle bir yazmayı nasıl başarabilirsin?
Mikayil Abdullayev

1
@MikayilAbdullayev teşekkürler! Sadece "önemli soruları" cevaplama eğilimindeyim ve yeni yeni şeyler öğrendikçe onlara tekrar tekrar gelme eğilimindeyim.
Ciro Santilli

31

CPU bağlı, programın CPU veya merkezi işlem birimi tarafından tıkanmış olduğu anlamına gelirken, I / O bağlı programın G / Ç tarafından veya darbelere, ağa okuma veya yazma gibi giriş / çıkışla tıkanmış olduğu anlamına gelir.

Genel olarak, bilgisayar programlarını optimize ederken, darboğazı araştırmaya ve ortadan kaldırmaya çalışır. Programınızın CPU'ya bağlı olduğunu bilmek, birinin başka bir şeyi gereksiz yere optimize etmemesine yardımcı olur.

[Ve “darboğaz” ile, programınızı aksi takdirde olduğundan daha yavaş yapan şey demek istiyorum.]


22

Aynı fikri ifade etmenin başka bir yolu:

  • CPU'yu hızlandırmak programınızı hızlandırmazsa, G / Ç'ye bağlı olabilir.

  • G / Ç'yi hızlandırmak (örneğin daha hızlı bir disk kullanmak) yardımcı olmazsa, programınız CPU'ya bağlı olabilir.

("Olabilir" i kullandım çünkü diğer kaynakları dikkate almanız gerekiyor. Bellek bir örnektir.)


11

Programınız G / Ç'yi beklerken (örn. Bir disk okuma / yazma veya ağ okuma / yazma vb.), CPU, programınız durdurulmuş olsa bile diğer görevleri yapmakta serbesttir. Programınızın hızı çoğunlukla G / Ç'nin ne kadar hızlı olabileceğine bağlı olacaktır ve hızlandırmak isterseniz G / Ç'yi hızlandırmanız gerekecektir.

Programınız çok sayıda program talimatı çalıştırıyorsa ve G / Ç'yi beklemiyorsa, CPU'ya bağlı olduğu söylenir. CPU'nun hızlandırılması, programın daha hızlı çalışmasını sağlayacaktır.

Her iki durumda da, programı hızlandırmanın anahtarı donanımı hızlandırmak değil, programı ihtiyaç duyduğu IO veya CPU miktarını azaltmak için optimize etmek veya CPU yoğun olsa da I / O yapmasını sağlamak olabilir. şey.


6

G / Ç sınırı, bir hesaplamayı tamamlamak için geçen sürenin temel olarak giriş / çıkış işlemlerinin tamamlanmasını beklemek için harcanan süre ile belirlendiği bir koşulu belirtir.

Bu, CPU'ya bağlı bir görevin tersidir. Bu durum, verilerin talep edilme oranı, tüketilen orandan daha yavaş olduğunda veya başka bir deyişle, veri istemekten daha çok zaman harcamakla ortaya çıkar.


6

GÇ bağlı süreçler: GÇ yapmak için hesaplamalardan daha fazla zaman harcayın, birçok kısa CPU patlaması yapın. CPU bağlantılı süreçler: hesaplama yapmak için daha fazla zaman harcayın, çok az sayıda CPU patlaması yapın


2

Microsoft'un söylediklerine bakın.

Eşzamansız programlamanın özü, eşzamansız işlemleri modelleyen Görev ve Görev nesneleridir. Bunlar zaman uyumsuz tarafından desteklenir ve anahtar kelimeler beklenir. Model çoğu durumda oldukça basittir:

  • G / Ç bağlantılı kod için, zaman uyumsuz bir yöntemin içinde bir Görev veya Görev döndüren bir işlem beklersiniz.

  • CPU'ya bağlı kod için, arka plan iş parçacığında Task.Run yöntemiyle başlatılan bir işlem beklersiniz.

Await anahtar kelimesi büyünün gerçekleştiği yerdir. Beklenen yöntemi arayan kişinin kontrolünü sağlar ve sonuçta bir kullanıcı arayüzünün duyarlı olmasına veya bir servisin elastik olmasına izin verir.

G / Ç Bağlama Örneği: Bir web hizmetinden veri indirme

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

CPU'ya Bağlı Örnek: Bir Oyun için Hesaplama Yapma

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

Yukarıdaki örnekler, I / O bağlantılı ve CPU bağlantılı işleri nasıl zaman uyumsuz kullanabileceğinizi ve bekleyebileceğinizi göstermiştir. Yapmanız gereken bir işin G / Ç veya CPU'ya bağlı olduğunu belirleyebileceğiniz anahtardır, çünkü kodunuzun performansını büyük ölçüde etkileyebilir ve belirli yapıların yanlış kullanılmasına neden olabilir.

Herhangi bir kod yazmadan önce sormanız gereken iki soru:

Kodunuz veritabanındaki veriler gibi bir şeyi "bekliyor" olacak mı?

  • Cevabınız "evet" ise, çalışmanız I / O sınırlıdır.

Kodunuz çok pahalı bir hesaplama mı yapacak?

  • "Evet" yanıtı verdiyseniz, çalışmanız CPU'ya bağlıdır.

Yaptığınız iş I / O bağlıysa, zaman uyumsuz kullanın ve Task.Run olmadan bekleyin . Görev Paralel Kitaplığı'nı kullanmamalısınız. Bunun nedeni Async in Depth (Derinlik makalesinde) makalesinde ana hatlarıyla verilmiştir .

Yaptığınız iş CPU'ya bağlıysa ve yanıt vermeyi önemsiyorsanız, zaman uyumsuzluğu kullanın ve bekleyin ancak işi Task.Run ile başka bir iş parçacığında ortaya çıkarın. Çalışma eşzamanlılık ve paralellik için uygunsa, Görev Paralel Kütüphanesini de kullanmayı düşünmelisiniz .


2

Uygulama sırasında aritmetik / mantıksal / kayan nokta (A / L / FP) performansı çoğunlukla işlemcinin teorik tepe performansına yakın olduğunda (üretici tarafından sağlanan ve işlemci: çekirdek sayısı, frekans, kayıtlar, ALU'lar, FPU'lar vb.).

Peek performansının imkansız demediği için gerçek dünya uygulamalarında elde edilmesi çok zordur. Uygulamaların çoğu yürütmenin farklı bölümlerindeki belleğe erişir ve işlemci birkaç döngü sırasında A / L / FP işlemleri yapmaz. Bellek ve işlemci arasındaki mesafe nedeniyle buna Von Neumann Sınırlaması denir .

CPU tepe performansına yakın olmak istiyorsanız, ana bellekten veri gerektirmemesi için önbellek içindeki verilerin çoğunu yeniden kullanmaya çalışmak bir strateji olabilir. Bu özellikten yararlanan bir algoritma matris-matris çarpımıdır (eğer her iki matris de önbellekte saklanabilirse). Bunun nedeni, matrislerin boyutu büyükse, yalnızca FP sayıları kullanan işlemler n x nhakkında yapmanız gerektiğidir . Diğer yandan, örneğin, sadece aynı verilere sahip FLOP'ları gerektirdiğinden, matris eklemesi , matris çarpımından daha az CPU ya da daha fazla belleğe bağlı bir uygulamadır .2 n^32 n^2n^2

Aşağıdaki şekilde, bir Intel i5-9300H'de matris ilavesi ve matris çarpımı için naif bir algoritma ile elde edilen FLOP'lar gösterilmektedir:

Matris Toplama ve Matris Çarpımı arasındaki FLOP karşılaştırması

Beklendiği gibi matris çarpımının performansının matris ilavesinden daha büyük olduğunu unutmayın. Bu sonuçlar çalıştırılarak çoğaltılabilir test/gemmve test/mataddbu depoda bulunabilir .

Bu etki hakkında J. Dongarra tarafından verilen videoyu da izlemenizi öneririm .


1

G / Ç Bağlı işlemi: - Bir işlemin ömrünün büyük bir kısmı i / o durumunda harcanırsa, işlem a / o bağlı işlemdir. Örnek: -hesaplayıcı, internet explorer

CPU Bound işlemi: - İşlem ömrünün büyük bir kısmı cpu'da harcanırsa, cpu bağlantılı bir süreçtir.


8
Hesap makinesi ES'ye bağlı bir işlem nasıl olurdu? Elbette CPU'ya bağlı olacaktır. Hesap makinenizin çoğu zaman ağa veya diske erişerek engellenirse o zaman bir şeylerin yanlış olduğunu öneririm.
rickerbh

6
Hesap makinesi örneğinin açık olduğunu düşündüm: çoğu zaman kullanıcının bir düğmeye basmasını bekler, böylece G / Ç'yi bekler.
PSP

1
@psp doğru, ancak hesap makinesi örneğinin adı "hesap makinesi" nedeniyle io bağlı olarak görülmesi hala yüzeysel olarak zor. Bu, programın ana amacının uzun cpu hesaplamaları yapmak olduğu anlamına gelir, ancak masaüstünüzde hesap makinenize bakarsanız, yalnızca nanosaniye süren hesaplamaları yapan çok basit bir işlemdir. Bu yüzden çoğu zaman kullanıcı girişi olan IO'yu bekler.
Calicoder
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.