C Performansı için Yazma? [kapalı]


32

C'nin genellikle C ++ 'a göre performans avantajı olduğunu çok sık duyduğumu biliyorum. MSVC'nin en yeni C standardını desteklemediğini bile fark edene kadar başka hiçbir şey düşünmedim, ama en yenisi C99'u (bildiğim kadarıyla) destekliyor.

Yeniden kullanabilmem için OpenGL'de işlemek için bazı kodlar içeren bir kütüphane yazmayı planlıyordum. Kütüphaneye C yazmayı düşünüyordum, çünkü performans konusunda herhangi bir grafikte artış yaşanıyor.

Ama buna gerçekten değecek mi? Kütüphaneyi kullanan kod büyük olasılıkla C ++ ile yazılmış ve genel olarak C ++ ile kodlamayı tercih ediyorum.

Ancak, performansta küçük bir fark bile olsa, C ile giderdim.

Ayrıca bu kütüphanenin Windows / OS X / Linux üzerinde çalışacağım bir şey olacağı ve muhtemelen her şeyi yerel olarak derleyeceğim (Windows için MSVC, OS X için Clang veya GCC ve Linux için GCC .. belki de Intel'in her şey için derleyicileri).

Etrafa baktım ve bazı ölçütler buldum, ama gördüğüm her şey MSVC ve Clang yerine GCC ile ilgilendi. Ayrıca, ölçütler kullanılan dillerin standartlarından bahsetmiyor. Bu konuda bir fikri olan var mı?

DÜZENLE:Birkaç yıl daha tecrübeli olduktan sonra sadece bu konudaki bakış açımı paylaşmak istedim. Bu soruyu sorduğum projeyi C ++ 'da yazdım. Başka bir projeye C ile aynı anda başlamıştım, elde edebileceğimiz herhangi bir küçük performansın elde edilmesini istiyordum ve projenin C'de bağlanması gerekiyordu. Birkaç ay önce haritalara gerçekten ihtiyaç duyduğum bir noktaya ulaştım. dize manipülasyonu. C ++ standart kütüphanesinde bunun yeteneklerini biliyordum ve nihayetinde standart kütüphanedeki bu yapıların makul bir sürede C de uygulayabileceğim haritalar ve dizgilerden daha iyi performans göstereceği ve daha istikrarlı olacağı sonucuna vardım. C ile bağlanabilir olma zorunluluğu, opak tiplerle hızlı bir şekilde yapılan C ++ koduna bir C arayüzü yazılarak kolayca karşılandı. Kütüphaneyi C ++ ile yeniden yazmak, C'ye yazarken olduğundan çok daha hızlı gibiydi ve özellikle bellek sızıntısı gibi hatalara daha az eğilimli görünüyordu. Ayrıca platforma özgü uygulamaları kullanmaktan çok daha kolay olan standart kütüphane ipliği kütüphanesini de kullanabildim. Sonunda, kütüphaneyi C ++ 'da yazmanın, muhtemelen küçük bir performans maliyeti ile büyük faydalar sağladığına inanıyorum. Henüz C ++ sürümünü kıyaslamamıştım, ancak yazdığımdan standart kütüphane veri yapılarını kullanarak bazı performanslar kazanmamın mümkün olabileceğine inanıyorum. Kütüphaneyi C ++ 'da yazmanın, muhtemelen küçük bir performans maliyeti ile büyük faydalar sağladığına inanıyorum. Henüz C ++ sürümünü kıyaslamamıştım, ancak yazdığımdan standart kütüphane veri yapılarını kullanarak bazı performanslar kazanmamın mümkün olabileceğine inanıyorum. Kütüphaneyi C ++ 'da yazmanın, muhtemelen küçük bir performans maliyeti ile büyük faydalar sağladığına inanıyorum. Henüz C ++ sürümünü kıyaslamamıştım, ancak yazdığımdan standart kütüphane veri yapılarını kullanarak bazı performanslar kazanmamın mümkün olabileceğine inanıyorum.


9
En yeni MSVC desteği aslında C89'dur.
4'te

4
@detly Visual Studio 2013'te, C99 özelliklerinin büyük çoğunluğu desteklenmektedir . Tam destek değil, ama pratikte bahse girerim C99 yazmak için kullanmak sorun değil.
congusbongus

4
@ danielu13 - C ++ 'ın C ++' a göre bir performans avantajı olduğunu tam olarak nereden duydunuz?
Ramhound

1
@ Sebastian-LaurenţiuPlesciuc Bu linklerin gerçekten faydalı olduğunu sanmıyorum. Birincisi, hemen hemen aynı soru ile programmers.stackexchange.com/q/113295/76444, ancak bağlantınızdaki c yerine c ++ lehine iyi karşılanabilir . 2. bağlantınız için, sadece linus torvalds bir rant. İnşallah herkes artık c ++ 'dan nefret etmeyi çok sevdiğini ve bir sopayla dokunmayacağını biliyor ama c ++ ile ilgili hevesleri pek nesnel değil, kişisel görüş ve önyargılarla doludur ve dilin gerçekliğini yansıtmamaktadır. . En azından benim fikrim bu .
user1942027

1
@RaphaelMiedl Ayrıca uzun zaman önce 2007 yılında yazıldığından bahsetmiştim, C ++ derleyicileri ve C ++ dili o zamandan beri gelişti. Ne olursa olsun, hangi dili kullanacağını seçmek programcının elinde.
Sebastian-Laurenţiu Plesciuc

Yanıtlar:


89

Sanırım, insanlar genellikle C'nin C ++ 'dan daha hızlı olduğunu iddia ediyorlar çünkü C' deki performans hakkında mantıklı olmak daha kolay . C ++ doğal olarak daha yavaş veya daha hızlı değil, ancak bazı C ++ kodları gizli performans cezalarını gizleyebilir. Örneğin, bir parça C ++ koduna bakıldığında hemen görünmeyen kopyalar ve örtük dönüşümler olabilir.

Aşağıdaki ifadeyi ele alalım:

foo->doSomething(a + 5, *c);

Ayrıca doSomething, aşağıdaki imzaya sahip olduğunu varsayalım :

void doSomething(int a, long b);

Şimdi, bu özel ifadenin olası performans etkisini analiz etmeye çalışalım.

C de, sonuçları oldukça açık. fooyalnızca yapıya doSomethingbir işaretçi olabilir ve bir işleve işaretçi olmalıdır. *cuzun zamandır başvuruları kaldırır ve a + 5tamsayıdır. Tek belirsizlik, şu türden gelir a: Bir int değilse, bir dönüşüm olacaktır. ama bunun dışında, bu tek ifadenin performans etkisini ölçmek kolaydır.

Şimdi C ++ 'a geçelim. Aynı ifade şimdi çok farklı performans özelliklerine sahip olabilir:

  1. doSomethingsanal olmayan üye işlevi (ucuz), sanal üye işlevi (biraz daha pahalı) std::function, lambda ... vb. fooolabilir . Daha da kötüsü, operator->bilinmeyen karmaşıklığın çalışmasıyla aşırı yüklenen bir sınıf tipi olabilir . Bu nedenle, aramanın ücretini ölçmek için doSomething, şimdi foove ' nin tam yapısını bilmek gerekir doSomething.
  2. abir tamsayı veya bir tamsayıya referans (ek dolaylı) veya uygulayan bir sınıf olabilir operator+(int). Operatör, üstü kapalı bir şekilde dönüştürülebilen başka bir sınıf tipi bile geri verebilir int. Yine, performans maliyeti sadece açıklamada açık değildir.
  3. cBir sınıf tipi uygulama olabilir operator*(). Aynı zamanda long*vb. İçin bir referans olabilir .

Resmi aldın. Nedeniyle C ++ 'ın dil özellikleri nedeniyle, çok zor bu aynen soyutlamalar ek olarak C. Asistan'da olandan tek ifadenin performans maliyetlerini ölçmek için ise std::vector, std::stringgenellikle kendi performans özelliklerine sahip olan, C ++ kullanılan ve gizlemek dinamik hafıza tahsisleri vardır ( ayrıca @ Ian'ın cevabına bakınız).

Yani, sonuç şu: Genel olarak, C veya C ++ kullanılarak elde edilebilecek performansta bir fark yoktur. Ancak, gerçekten performans açısından kritik olan kod için, insanlar genellikle C kullanmayı tercih ederler, çünkü daha az olası gizli performans cezaları vardır.


1
Mükemmel cevap Cevabımda söylediğim şey buydu, ama bunu daha iyi açıkladın.
Ian Goldby

4
Bu gerçekten kabul edilen cevap olmalı. "C, C ++ 'dan daha hızlı" gibi ifadelerin neden var olduğunu açıklar. C, C ++ 'dan daha hızlı veya daha yavaş olabilir, ancak belirli bir C kodunun neden hızlı / yavaş olduğunu anlamak genellikle daha kolaydır, bu da genellikle optimize etmeyi kolaylaştırır.
Leo,

Bu mükemmel cevaptan hiçbir şey almamak (benden bir +1), ancak derleyici (ler) bu karşılaştırmada elmalar ve portakallar olabilir. C / C ++ için aynı kod üretebilir veya üretemezler. Elbette aynı şey, iki fiziksel derleyici veya derleyici seçeneği için de söylenebilir, hatta fiziksel olarak aynı programı aynı kaynak dil varsayımlarıyla derlerken bile.
JRobert

4
C ++ çalışma sürelerinin çoğunun, eşdeğer C çalışma zamanına kıyasla çok büyük olduğunu ve bellek kısıtlı olmanızın bir önemi olmadığını da eklerdim.
James Anderson,

@JamesAnderson Eğer gerçekten o kadar hafıza kısıtlı iseniz, muhtemelen hiç bir çalışma zamanına ihtiyacınız yoktur :)
Navin

30

C ++ ile yazılmış kod, belirli görev türleri için C'den daha hızlı olabilir.

C ++ 'ı tercih ediyorsanız, C ++' ı kullanın. Herhangi bir performans sorunu, yazılımınızın algoritmik kararlarına kıyasla önemsiz olacak.


6
Daha hızlı olabilir, ancak aynı sebepten daha hızlı olmayabilir.
Rob,

C ++ 'ta optimize edilmiş C'den daha hızlı olan bazı optimize kod örnekleri verebilir misiniz?

1
@TomDworzanski: Bir örnek, şablonlar kullanılarak, kod yolları hakkındaki kararların derleme zamanında tespit edilebildiği ve sonuçta, c. işlev çağrıları satır içi yoluyla önlemek için.
whatsisname,

23

C ++ 'ın tasarım ilkelerinden biri, kullanmadığınız özellikler için ödeme yapmamanızdır. Bu nedenle, C ++ dilinde kod yazarsanız ve C'de bulunmayan özelliklerden kaçınırsanız, sonuçta derlenen kodun performansta aynı olması gerekir (bunu ölçmeniz gerekir).

Sınıfları kullanmanın, örneğin yapılara ve bir dizi ilişkili fonksiyona kıyasla ihmal edilebilir bir maliyeti vardır. Sanal işlevler biraz daha pahalıya mal olacak ve uygulamanız için önemli olup olmadığını görmek için performansı ölçmeniz gerekir. Aynı diğer C ++ dilleri için de geçerlidir.


3
Sanal işlev gönderme ek yükü neredeyse yok denecek kadar azdır, aksi takdirde WAY den denize düşme ve şeyleri sanallaştırma konusunda yapmadıysanız. Vtables, kodunuzun ve verilerinizin geri kalanına kıyasla küçük olacak ve vtable aracılığıyla indekslenmiş dal her rutin atama için birkaç saat ekleyecektir. Her şey dahil olmak üzere, rutin çağrılar, geri arama çağrısı, birkaç yüz ila birkaç milyon saat arasında bir yerde olacağı göz önüne alındığında, söz konusu şube gürültü tabanına gömülecek.
John R. Strohm

6
Yapılar C ++ 'da sınıflardır.
sağa dönüş

2
@rightfold: Tabii, ancak thisişaretçi dili özelliğini kullanmadan işaretçilerin çevresinden geçen C ++ kodunu yazabilirsiniz . Bütün söylediğim buydu.
Greg Hewgill

4
@John Gerçek maliyet değil (bazı işlemcilerin önyüklemesini biraz zorlaştıracağından emin olmama rağmen), ancak sanal işlevlerin (en azından C ++ 'da) başka türlü mümkün olmayana izin vermeyeceği gerçeği optimizasyonları. Ve evet, bu performans üzerinde devasa bir etkiye sahip olabilir.
Voo

2
@Voo Adil olmak gerekirse, aynı şey eşdeğer C kodu (çalışma zamanı polimorfizmini manuel olarak taklit eden kod) için de söylenebilir. En büyük fark, bir derleyicinin, söz konusu işlevin C ++ 'da sıralanıp satılamayacağını belirlemesinin daha kolay olacağını düşünüyorum.
Thomas Eding,

14

Daha yüksek seviyeli dillerin bazen daha yavaş olmasının bir nedeni, daha düşük seviyeli dillerden çok, sahnelerin arkasına saklanabilmeleridir.

Düşük seviye detaylarını kaldıran herhangi bir dil (veya kütüphane, API, vb.) Potansiyel olarak pahalı işlemleri gizliyor olabilir. Örneğin, bazı dillerde sadece bir dizgeden takip eden boşlukları kırpmak bir bellek tahsisi ve dizgenin bir kopyasıyla sonuçlanır. Özellikle bellek tahsisi ve kopyalanması, sıkı bir döngüde tekrar tekrar oluyorlarsa pahalı olabilir.

Bu tür bir kodu C dilinde yazdıysanız, bariz bir şekilde açıktı. C ++ 'da muhtemelen daha az, çünkü tahsisler ve kopyalamalar bir yerde bir sınıfa çekilebilir. Hatta masum görünümlü aşırı yüklenmiş bir operatörün veya kopya kurucusunun arkasına gizlenmiş bile olabilirler.

Yani, isterseniz C ++ kullanın. Ama onların altında ne olduğunu bilmediğin zaman soyutlamaların görünüşte göründüğü kolaylık ile kandırılma.

Elbette, kodunuzu gerçekten yavaşlatan şeyin ne olduğunu bulmak için bir profilleyici kullanın.


5

Buna değer olarak, gelişmiş özellik kümesi için kütüphanelerimi C ++ 11 ile yazmaya meyilliyim. Paylaşılan işaretçiler, istisnalar, genel programlama ve yalnızca diğer C ++ özelliklerinden yararlanabilmeyi seviyorum. C ++ 11'i seviyorum, çünkü önemsediğim platformların çoğunun desteklendiğini gördüm. Visual Studio 2013'ün birçok ana dili özelliği ve kütüphane uygulaması kullanıma hazır ve sözde geri kalanı eklemek için çalışıyor. Bildiğiniz gibi, Clang ve GCC, tüm özellik setini de destekliyor.

Bununla birlikte, geçenlerde doğrudan sorgunuzla alakalı olduğunu düşündüğüm kütüphane geliştirme ile ilgili gerçekten harika bir strateji okudum. Makalede, "C ++ istisnalarıyla iyi oynayan AC hata işleme stili" başlıklı Stefanu Du Toit, bu stratejiyi "kum saati" deseni olarak adlandırıyor. Makalenin ilk paragrafı:

"Kum saati" deseni dediğim şeyi kullanarak çok sayıda kütüphane kodu yazdım: Bir kütüphane uyguluyorum (benim durumumda, genellikle C ++ kullanarak), kütüphaneye tek giriş noktası haline gelen bir C API'sine sarın, daha sonra, zengin bir soyutlama ve uygun bir sözdizimi sağlamak için bu C API'yi C ++ veya diğer dillere sarın. Yerel platformlar arası kod söz konusu olduğunda, C API'ler, benzersiz ABI kararlılığı ve FFI'ler aracılığıyla diğer dillere taşınabilirlik sağlar. Hatta API'yi, çok çeşitli FFI'lara taşınabilir olduğunu bildiğim bir C altkümesiyle sınırlandırıyorum ve kütüphaneyi iç veri yapılarında meydana gelen değişikliklerden sızıntılara karşı korudum - gelecekteki blog yazılarında daha fazlasını bekliyoruz.


Şimdi öncelikli endişenizi ele almak için: performans.

Buradaki diğer cevapların çoğunda olduğu gibi, her iki dilde de kod yazmanın performans açısından da işe yarayacağını düşünüyorum. Kişisel bir bakış açısından, C ++ dilinde doğru kod yazmayı dil özellikleri nedeniyle daha kolay buluyorum, ancak bunun kişisel bir tercih olduğunu düşünüyorum. Her iki durumda da, derleyiciler gerçekten zekidir ve sizden daha iyi kod yazma eğilimindedir. Derleyicinin kodunuzu elinizden daha iyi optimize edeceği söylenebilir.

Birçok programcının bunu söylediğini biliyorum, ancak yapmanız gereken ilk şey kodunuzu yazmak, ardından onu profillemek ve profilleyicinizin önerdiği yerde optimizasyon yapmak. Zaman harcayarak özelliklerinizi geliştirmek için harcadığınız zaman daha iyi olacak ve ardından darboğazlarınızın nerede olduğunu görebildiğiniz zaman en iyi hale getireceksiniz.


Şimdi, dil özellikleri ve optimizasyonlarının gerçekten sizin lehinize nasıl işleyebileceği hakkında bazı eğlenceli okumalar için:

std :: unique_ptr sıfır yükü var

constexp derleme zamanı hesaplamasına izin verir

anlambilim taşıma gereksiz geçici nesneleri önlemek


std::unique_ptr has zero overheadBu muhtemelen doğru olamaz (teknik olarak konuşur) çünkü eğer bir istisna nedeniyle çözülürse yapıcısının çağrılması gerekir. Ham bir işaretçi bu ek yüke sahip değildir ve kodunuz muhtemelen atmayacaksa yine de doğru olacaktır. Bir derleyici genel durumda bunu kanıtlayamaz.
Thomas Eding,

2
@ThomasEding İstisnasız kod ile ilgili genel olarak boyut ve çalışma zamanı yüküne atıfta bulunuyordum. Hatalıysam beni düzelt, ancak istisnalar atılmadığında, istisnaların hala gerektiğinde kullanılmasına izin veren sıfır çalışma zamanı ek yükü olan yürütme modelleri var. Öyle olsa bile, ne zaman bir kurucu istisna atılabilir unique_ptr? Bildirildi noexceptve en azından tüm istisnaları ele alıyor, ancak ilk başta ne tür bir istisna atılabileceğini bile düşünemiyorum.
vmrob

vmrob: Afedersiniz ... "Oluşturucu" yerine "yıkıcı" yazmak istedim. Ben de "kanıtlanmayacak" demeyi kastetmiştim. Eeek!
Thomas Eding

2
@TalmasEding Bilirsiniz, yıkıcının bir istisna atması bile önemli olacağını sanmıyorum. Yıkıcı herhangi yeni bir istisna getirmediği sürece, hala sıfır gider. Dahası, tüm tahrip edicilerin optimizasyonlarla tek bir silme / ücretsiz çağrıya yönlendirildiğine inanıyorum.
vmrob

4

C ++ ve C arasındaki performans farkı, kesinlikle konuşulan dildeki herhangi bir şeyden değil, sizi ne yapmaya teşvik ettiğinden kaynaklanmaktadır. Nakit paraya karşılık bir kredi kartı gibi. Daha fazla harcama yapmaz, ancak çok disiplinli olmadığınız sürece yine de yaparsınız.

İşte C ++ ile yazılmış ve daha sonra agresif bir performansa ayarlanmış bir program örneği . Dil ne olursa olsun agresif performans ayarlaması yapmayı bilmeniz gerekir. Kullandığım yöntem bu videoda gösterildiği gibi rastgele duraklatmadır.

C ++ 'ın yapmaya teşvik ettiği pahalı şeyler, aşırı bellek yönetimi, bildirim tarzı programlama, programınızın çok katmanlı soyutlama kitaplıklarına (@anan'ın söylediği gibi), yavaşlık gizlemeye vb. Güvenmesidir.


2

Her iki dilde de aynı şeyi yaparsanız, C ++ ile karşılaştırıldığında hiçbir performans avantajına sahip değildir. İyi bir C programcısı tarafından yazılmış herhangi bir eski C kodunu alabilir ve geçerli ve eşdeğer bir C ++ koduna dönüştürebilirsiniz (hem siz hem de derleyiciniz "restrict" anahtar kelimenin ne yaptığını ve etkili bir şekilde kullanmıyorsanız, ama çoğu insan yok).

C ++, (1) kitaplığı kullanmadan çok daha hızlı ve kolay yapılabilecek işleri yapmak için standart C ++ kitaplığını kullanırsanız ya da (2) standart C ++ kitaplığını kullanıyorsanız, daha yavaş ya da daha hızlı bir şekilde farklı performanslara sahip olabilir. Kitaplığı kötü C'de yeniden yerleştirmekten çok daha kolay ve hızlı şeyler yapmak


1
bu, önceki 6
cevapta

Bence bu cevap başkasının bahsetmediği önemli bir noktaya değiniyor. İlk bakışta, C ++ 'ın C'nin bir üst kümesi olduğu görülüyor, bu nedenle hızlı bir C uygulaması yazabiliyorsanız, eşdeğer bir C ++ uygulaması yazmanız gerekir. Bununla birlikte, C99, istenmeyen işaretçi takma adlarının engellenmesini sağlayan restrict anahtar sözcüğünü destekler. C ++ böyle bir desteğe sahip değil. İşaretçi takma adından kaçınmak, Fortran'ın yüksek performanslı uygulamalar için kullanışlı olmasını sağlayan önemli bir özelliğidir. Benzer alanlarda C99'dan C ++ 'dan daha iyi performans elde etmenin de mümkün olacağını bekliyorum.
user27539
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.