2015-04-17 20 views
5

Bir derleyicinin optimizasyonlarının oldukça ezoterik olabileceğini biliyorum, ama benim örneğim o kadar basit ki Anlayabiliyor mu, anlamak istediğim bir şey varsa, görmek isterim.Derleyici getline'ı() etkili bir şekilde nasıl optimize eder?

500 mb metin dosyasına sahibim. Bir fstream'i bildirip başlatıyorum: Dosyayı sırayla okumam gerekiyor. Bu sekme sınırlandırılmış, ancak alan uzunlukları bilinmemekte ve hattan çizgiye değişmektedir. Her satır için yapmam gereken asıl ayrıştırma, toplama çok az zaman ekledi (bu, string yaptığımdan beri beni gerçekten şaşırttı: getline'dan her satırda buldum. Bu yavaş olacağını düşündüm).

Genel olarak, her satırın bir dizgisini aramak ve bulduğumda döngüden çıkmak istiyorum. Ayrıca, kendi merakım için satır numaralarını artırıp tükürdüğümde, bunun kısa bir zaman aldığını doğruladım (5 saniye ya da öylesine) ve kısa çizgileri nasıl geçtiğini ve uzun çizgileri yavaşlattığını görmeme izin verdim.

eof etiketleme benzersiz dizesi olarak bulunacak metni aldım, bu yüzden her satırı araması gerekiyor. Bunu telefonumda yapıyorum, bu yüzden biçimlendirme sorunları için özür dilerim ancak oldukça basittir. Fstream'i referans olarak alan ve string olarak bulunacak bir metin ve std :: size_t döndüren bir işlev var.

long long int lineNum = 0; 
while (std::getline (file, line)) 
{ 
    pos = line.find(text); 
    lineNum += 1; 
    std::cout << std::to_string(lineNum) << std::endl; 
    if (pos != -1) 
     return file.tellg(): 
} 
    return std::string::npos; 

Düzenleme: lingxi, to_string'in burada gerekli olmadığını belirtti, teşekkürler. Bahsedildiği gibi, hat numarası hesaplaması ve çıkışı tamamen atlamak, birkaç saniyeden tasarruf edilmesini sağlar; bu, benim tahmin edilen örneğimde toplamın küçük bir yüzdesidir.

Bu, her satırda başarılı bir şekilde çalışır ve son konumu 408 saniye içinde döndürür. Dosyayı bir stringstream'e yerleştirmeye veya tüm döngüdeki her şeyi atlamaya çalışarak (iyileştirme, arama ya da gösterme işlemi yapana kadar sadece bir satır doldu) en az iyileştirme yaptım. Ayrıca dize için büyük bir yer ayırmak da yardımcı olmadı.

Getline tamamen sürücü gibi görünüyor. Ancak .../O2 bayrağını (MSVC++) derlediğimde, 26 saniyede daha hızlı bir şekilde elde ediyorum. Buna ek olarak, kısa çizgilerdeki kısa çizgilerde belirgin bir yavaşlama yoktur. Açıkçası derleyici çok farklı bir şey yapıyor. Benden hiçbir şikayette bulunmadım, ancak nasıl elde edildiğine dair herhangi bir düşünce var mı? Bir alıştırma olarak, derleyici optimizasyonundan önce kodumu daha hızlı yürütmeye çalışmak istiyorum.

Bahse girerim, getline dizgiyi nasıl işleyeceği ile ilgili bir şey vardır. Daha hızlı (alas bir süre için test edemez) sadece dizge için tüm dosyaları saklamak ve karakter karakterini okuyarak,/n geçirdiğimde satır numaramı arttırmak mı? Ayrıca, derleyici mmap gibi şeyler kullanır mı?

GÜNCELLEME: Bu akşam eve geldiğimde kodu göndereceğim. Çalışma zamanı kontrollerinin kapatılması, yürütmeyi 400 saniyeden 50 saniyeye düşürdü! Ham c stili dizileri kullanarak aynı işlevselliği gerçekleştirmeyi denedim. Süper deneyimli değilim, ama verileri bir karakter dizisine dökmek yeterince kolaydı, ve onu yeni satırlar veya hedef dizgimin ilk harfini aramaya başladım.

Tam hata ayıklama modunda bile sonuna kadar ulaşır ve dizeyi doğru olarak 54 saniye içinde bulur. Kontroller 26 saniye ve 20 saniye optimize edildi. Yani, gayri resmi, özel deneylerimden, dizi ve akış fonksiyonlarının çalışma zamanı kontrolleri tarafından kurban edilmesine benziyor mu? Tekrar eve döndüğümde kontrol edeceğim.

+0

C++ hızlıdır, yo. – Barry

+0

Sadece "std :: cout << lineNum << std :: endl;'. .burada biraz zaman kazandırabilir. – Lingxi

+1

Birisi ilk kez iostreams "hızlı" dediğimi görmeliyim. Olasılıklar arasında hata ayıklama kontrollerinin (MSVC'nin standart kütüphanesi bunlardan çok), daha iyi satır içi, devirtualizasyon vardır. –

cevap

1

Bu çarpıcı hızın nedeni, iostream sınıf hiyerarşisinin şablonlara dayandığıdır (std::ostream aslında std::basic_ostream adı verilen bir şablonun yazım hatasıdır) ve kodlarının çoğu üstbilgide. C++ iostreams, akıştaki her baytı işlemek için çeşitli işlev çağrıları alır. Bununla birlikte, bu işlevlerin çoğu oldukça önemsizdir. Optimizasyonu açarak, bu çağrıların çoğu derlenerek, std::getline'un karakterleri bir satırdan diğerine yeni bir satır bulana kadar kopyalar. Normalde bu, birçok işlev çağrısı katmanı altında "gizlenir". Bu, daha da optimize edilebilir ve büyüklük sıralarıyla bayt başına düşen yükü azaltır.

Arabellekleme davranışı, optimize edilmiş ve optimize edilmemiş sürüm arasında gerçekten değişmez, aksi takdirde hız daha da yüksek olur.

+0

MSVC gibi bir LTO derleyicisi de tüm programa bakabilir ve sanal işlev çağrılarını doğrudan aramalara dönüştürebilir. Bu da iostreams çok yardımcı olur. –

+0

"Bu dramatik hızlanma sebebi" - ne kadar hızlı bir hız? Q, optimizasyonu hızlandırmayı "komik" olarak tanımlar. I/O, kodu * vurgulamak için yeterince hızlı gerçekleştirilebiliyorsa, optimizasyon iostream'lerin performansı için gerçekten önemlidir. Fakat gerçek disk okumaları, gözlenen performansın göreceli olarak tutarlı olduğu aynı büyüklükteki tamponlu parçalarda yapılır. OP –

+0

OP numaralarını okuyorsanız,/O2 tuşunu kullanarak çalışma süresini 20'lik bir faktöre indirgiyorsunuz. Mesajın geri kalanından OP'nin bu kadar büyük bir hızlanma beklemediği ve "daha hızlı" olmasının gerçekten garip bir yolu olduğu oldukça açık. "dramatik olarak daha hızlı" diyor. –

İlgili konular