Bir bilgisayar saniyede bir milyon işlem yapıyorsa, (int I = 0; I < 1000000; I++) {cout <<I;} işlemi neden sonsuza kadar sürüyor?
ŞU programı C veya C++ dilinde yazmış olsaydınız (örneğin):
for ( int i = 0 ; i < 1000000 ; i++ ) x += i ;
(0'dan 1000000'e kadar olan tüm sayıları ekrana göndermek yerine, onları toplayacak şekilde kodunuzu değiştirdiğimi fark edin - bu ÇOK önemlidir!)
…ve bunu makine koduna derleseydi, bilgisayarın şunları yapması gerekirdi:
'i'nin hala bir milyondan küçük olup olmadığını test edin.
'x'e 'i' ekleyin
'i'ye bir ekle
Başa dön ve her şeyi tekrar yap.
Bu yaklaşık 4 makine kodu talimatıdır - her biri bir milyon kez yapılır - yaklaşık 4 milyon talimat. Ve bilgisayarınız saniyede MİLYARLARCA talimat yapabildiği için ÇOK hızlı gidecektir... modern bilgisayarlarda bir milisaniyenin çok altında.
Şimdi... tüm bunlar C veya C++ kullandığınızı ve programı makine koduna derlediğinizi varsayıyor.
Ama sen şunu dedin:
for ( int i = 0 ; i < 1000000 ; i++ ) cout << i ;
İlk bakışta, “cout << i;” işleminin bilgisayar için “x += i ;” işleminden daha zor olmadığı görülüyor - ama öyle!
Bilgisayarın sizin kodunuzun bir döngüsünü çalıştırmak için ne yapması gerektiğine bir bakalım:
'i'nin hala bir milyondan küçük olup olmadığını test edin.
'i'ye bir ekle
Standart çıktıya 'i' gönder. Bu da şunları gerektirir:
'i' sayısını 10 tabanlı ASCII karakterlerinden oluşan bir dizeye dönüştürmek ve bir boş sonlandırıcı eklemek... sayının negatif olup olmadığını kontrol etmek zorunda olan oldukça karmaşık bir fonksiyon gerektirir (değildir) ve ardından 'i'yi 10'a tekrar tekrar bölmek ve her bir basamağa '0' için ASCII kodunu eklemek gibi bir şey yapan bir döngü etrafında dolaşmak. Bu muhtemelen birkaç yüz makine kodu işlemidir - daha büyük sayılar için daha fazla, daha küçük sayılar için daha az.
Rakam dizisini "standart çıktı" akışına gönderme - bu, her bir ASCII sembolünü cout akış nesnesinin içindeki bir tampona kopyalamak için başka bir döngü içerir. Bir düzine daha talimat.
Tamponun dolu olup olmadığını kontrol etmek -ki bu muhtemelen her birkaç yüz döngüde bir gerçekleşecektir- ve eğer doluysa…
Tamponu pencereleme sistemine gönderiyorum...YÜZLERCE talimat.
Pencereleme sistemi, tamponun gönderileceği ekran penceresini belirleyecektir.
Şu anda kullanılan yazı tipini bulma.
Dizenizin sekme, geri alma ve yeni satır gibi şeyler içerip içermediğini veya kalın veya italik yazıya mı geçmeye çalıştığını kontrol edin.
Pencerenin yukarı kaydırılması gerektiğine karar verebilir - ve kaydırma çubuğunu güncellemesi ve diğer tüm şeyleri yukarı taşıması gerekecektir. Pencereyi fareyle manuel olarak kaydırabildiğinizden - ayrıca daha sonra geri kaydırabilmeniz için ekstra metninizi bir yere kaydetmesi gerekir. (Milyonlarca talimat!)
Daha sonra grafik kartınızın grafik aygıt sürücüsüne çağrılar yapıyor.
Bu da programınızın durumunu kaydedip daha sonra geri dönmesini gerektiren işletim sistemi çekirdek çağrılarına yol açacaktır (yüzlerce talimat)…
Bu muhtemelen başka bir programın çalıştırılması gerekip gerekmediğine bakmasına neden olacaktır. - ve belki de onları bir süre çalıştıracaktır (on milyonlarca talimat!).
Sonuç olarak, 'i' ondalık değerinin sembollerini oluşturan pikselleri çizme komutları GPU çipine gönderilmek üzere sıraya girer (muhtemelen yüzlerce talimat).
GPU boş olduğunda (başka bir program da çizim yapıyorsa bu biraz zaman alabilir) - pencerenizi güncellemek için gereken veriler, zaman olduğunda "DMA" mekanizması aracılığıyla GPU'ya gönderilir.
Bütün bunlardan dönün ve işletim sisteminin programınızı tekrar çalıştırma zamanının geldiğine karar vermesini bekleyin...
Ve SONUNDA…
Başa dön ve her şeyi tekrar yap.
Yani mesele şu ki - döngünün kendisi döngü başına yalnızca saniyenin milyarda birini alırken - döngünün içinde yaptığınız şey gerçekten, gerçekten karmaşık şeylerin meydana geldiği muazzam bir zincirleme reaksiyona neden olmaktı !
Programlama yaparken öğrenilmesi gereken en erken derslerden biri, Giriş/Çıkışın genellikle bir programın yaptığı en pahalı şey olduğudur.
Tek olasılık bu değil - standart çıktı akışını diskteki bir dosyaya yönlendirebilirdiniz... ki bu da bir sürü işlem, aygıt sürücüsü ve benzeri şeylerin ortaya çıkmasına neden olurdu.
Aslında, video oyunları gibi şeyler için - programın grafik çipiyle doğrudan veya dolaylı olarak konuşmasını sağlayarak tüm sürecin mümkün olduğunca kısa kesilmesi gerekir - bu da bu adımların birkaçı hariç hepsini ortadan kaldırır.
Bilgisayarlar inanılmaz hızlıdır - ama inanılmaz karmaşık şeyler yaparlar!
Kaynakça:Steve Baker
ŞU programı C veya C++ dilinde yazmış olsaydınız (örneğin):
for ( int i = 0 ; i < 1000000 ; i++ ) x += i ;
(0'dan 1000000'e kadar olan tüm sayıları ekrana göndermek yerine, onları toplayacak şekilde kodunuzu değiştirdiğimi fark edin - bu ÇOK önemlidir!)
…ve bunu makine koduna derleseydi, bilgisayarın şunları yapması gerekirdi:
'i'nin hala bir milyondan küçük olup olmadığını test edin.
'x'e 'i' ekleyin
'i'ye bir ekle
Başa dön ve her şeyi tekrar yap.
Bu yaklaşık 4 makine kodu talimatıdır - her biri bir milyon kez yapılır - yaklaşık 4 milyon talimat. Ve bilgisayarınız saniyede MİLYARLARCA talimat yapabildiği için ÇOK hızlı gidecektir... modern bilgisayarlarda bir milisaniyenin çok altında.
Şimdi... tüm bunlar C veya C++ kullandığınızı ve programı makine koduna derlediğinizi varsayıyor.
Ama sen şunu dedin:
for ( int i = 0 ; i < 1000000 ; i++ ) cout << i ;
İlk bakışta, “cout << i;” işleminin bilgisayar için “x += i ;” işleminden daha zor olmadığı görülüyor - ama öyle!
Bilgisayarın sizin kodunuzun bir döngüsünü çalıştırmak için ne yapması gerektiğine bir bakalım:
'i'nin hala bir milyondan küçük olup olmadığını test edin.
'i'ye bir ekle
Standart çıktıya 'i' gönder. Bu da şunları gerektirir:
'i' sayısını 10 tabanlı ASCII karakterlerinden oluşan bir dizeye dönüştürmek ve bir boş sonlandırıcı eklemek... sayının negatif olup olmadığını kontrol etmek zorunda olan oldukça karmaşık bir fonksiyon gerektirir (değildir) ve ardından 'i'yi 10'a tekrar tekrar bölmek ve her bir basamağa '0' için ASCII kodunu eklemek gibi bir şey yapan bir döngü etrafında dolaşmak. Bu muhtemelen birkaç yüz makine kodu işlemidir - daha büyük sayılar için daha fazla, daha küçük sayılar için daha az.
Rakam dizisini "standart çıktı" akışına gönderme - bu, her bir ASCII sembolünü cout akış nesnesinin içindeki bir tampona kopyalamak için başka bir döngü içerir. Bir düzine daha talimat.
Tamponun dolu olup olmadığını kontrol etmek -ki bu muhtemelen her birkaç yüz döngüde bir gerçekleşecektir- ve eğer doluysa…
Tamponu pencereleme sistemine gönderiyorum...YÜZLERCE talimat.
Pencereleme sistemi, tamponun gönderileceği ekran penceresini belirleyecektir.
Şu anda kullanılan yazı tipini bulma.
Dizenizin sekme, geri alma ve yeni satır gibi şeyler içerip içermediğini veya kalın veya italik yazıya mı geçmeye çalıştığını kontrol edin.
Pencerenin yukarı kaydırılması gerektiğine karar verebilir - ve kaydırma çubuğunu güncellemesi ve diğer tüm şeyleri yukarı taşıması gerekecektir. Pencereyi fareyle manuel olarak kaydırabildiğinizden - ayrıca daha sonra geri kaydırabilmeniz için ekstra metninizi bir yere kaydetmesi gerekir. (Milyonlarca talimat!)
Daha sonra grafik kartınızın grafik aygıt sürücüsüne çağrılar yapıyor.
Bu da programınızın durumunu kaydedip daha sonra geri dönmesini gerektiren işletim sistemi çekirdek çağrılarına yol açacaktır (yüzlerce talimat)…
Bu muhtemelen başka bir programın çalıştırılması gerekip gerekmediğine bakmasına neden olacaktır. - ve belki de onları bir süre çalıştıracaktır (on milyonlarca talimat!).
Sonuç olarak, 'i' ondalık değerinin sembollerini oluşturan pikselleri çizme komutları GPU çipine gönderilmek üzere sıraya girer (muhtemelen yüzlerce talimat).
GPU boş olduğunda (başka bir program da çizim yapıyorsa bu biraz zaman alabilir) - pencerenizi güncellemek için gereken veriler, zaman olduğunda "DMA" mekanizması aracılığıyla GPU'ya gönderilir.
Bütün bunlardan dönün ve işletim sisteminin programınızı tekrar çalıştırma zamanının geldiğine karar vermesini bekleyin...
Ve SONUNDA…
Başa dön ve her şeyi tekrar yap.
Yani mesele şu ki - döngünün kendisi döngü başına yalnızca saniyenin milyarda birini alırken - döngünün içinde yaptığınız şey gerçekten, gerçekten karmaşık şeylerin meydana geldiği muazzam bir zincirleme reaksiyona neden olmaktı !
Programlama yaparken öğrenilmesi gereken en erken derslerden biri, Giriş/Çıkışın genellikle bir programın yaptığı en pahalı şey olduğudur.
Tek olasılık bu değil - standart çıktı akışını diskteki bir dosyaya yönlendirebilirdiniz... ki bu da bir sürü işlem, aygıt sürücüsü ve benzeri şeylerin ortaya çıkmasına neden olurdu.
Aslında, video oyunları gibi şeyler için - programın grafik çipiyle doğrudan veya dolaylı olarak konuşmasını sağlayarak tüm sürecin mümkün olduğunca kısa kesilmesi gerekir - bu da bu adımların birkaçı hariç hepsini ortadan kaldırır.
Bilgisayarlar inanılmaz hızlıdır - ama inanılmaz karmaşık şeyler yaparlar!
Kaynakça:Steve Baker