C# vs. C++ - szybkość obliczeń

0

Witam,
mam do napisania program, który będzie kilkukrotnie przeszukiwał dane i przeprowadzał na nich stosunkowo proste obliczenia. Nie mam doświadczenia więc chciałbym dowiedzieć się czy wybór języka (C# albo C++) będzie miał istotny wpływ na szybkość wykonywania tych operacji?

Założenia:

  • język C++ lub C#
  • Windows Forms Application

Dane:

  • odzwierciedlenie struktury drzewa: obiekty węzłów i gałęzi
  • łącznie ponad 280 tys. obiektów, z których każdy ma w sobie kilkanaście zmiennych

Operacje:

  • wczytywanie i zapis danych w postaci 1 obiekt = 1 wiersz - format .txt
  • przeszukiwanie danych np. w celu identyfikacji powtórzeń
  • zastosowanie metod DFS i BFS (algorytmy przeszukiwania grafu)
  • kilka obliczeń (np. x=a+b*c^2) w ramach każdego z obiektów

Znalazłem kilka porównań, ale może ktoś jeszcze ma doświadczenia z podobnymi problemami? Który z tych języków lepiej nadaje się do napisania tego programu?

0

Istotny wpływ ma dobór algorytmów i implementacja, a nie język.

0
  • język C++ lub C#
  • Windows Forms Application

To jest żaden wybór, bo jeśli WinForms pod C++ to to będzie i tak działało na dotnecie (tzw. C++/CLI), więc prędkość będzie ta sama.
Co innego, gdybyś część obliczeniową zrobił w natywnym C++, a interfejs obojętnie w czym, ale czy warto tak kombinować? Chyba nie.

Napisz po prostu w C#, jak będzie za wolno to wtedy będziesz się martwił.

0

Pisz w C#, bo będzie prościej. Raczej nie ma co kombinować.
Pamiętaj tylko, że jeśli będziesz używał Visual Studio jako środowiska, warto przestawić opcję kompilacji z trybu Debug, na Release we właściwościach projektu. To może znacznie przyspieszyć wszelkie obliczenia (bo włączysz m.in. optymalizację kodu). U mnie czasami szybkość obliczeń wzrasta nawet 4-5 krotnie, przy bardziej złożonych algorytmach.

0

Na codzień rozwijam soft, który warstwę prezentacji ma napisaną w C# natomiast kluczowe obliczenia w natywnym c++. Pośrednikiem pomiędzy tymi warstwami jest kod napisany w zarządzanym C++. Z moich doświadczeń wynika, że jeśli kod musi tworzyć nowe obiekty klas oraz operować na składnikach tych klas, to różnica w szybkości pomiędzy C# a c++ wynosi 8-10x na korzyść natywnego C++. Oczywiście w Twoim wypadku nie musi być aż tak dużej różnicy. Wykonywałem też testy z wykorzystaniem zarządzanego c++ i czas wykonywania kodu jest wtedy zbliżony do C#.

0

Wykonywałem też testy z wykorzystaniem zarządzanego c++ i czas wykonywania kodu jest wtedy zbliżony do C#.

Bo zarządzany C++ jest kompilowany do IL - tak samo jak C#.

Z moich doświadczeń wynika, że jeśli kod musi tworzyć nowe obiekty klas oraz operować na składnikach tych klas, to różnica w szybkości pomiędzy C# a c++ wynosi 8-10x na korzyść natywnego C++.

Pokaż ten swój benchmark. Akurat alokacja ma sporą szansę być szybsza w C#. Wywoływanie metod to w gruncie rzeczy będzie to samo.

Pisz w C#. Jak wydajność będzie niewystarczająca - co odpowiednio zbadasz, np. za pomocą profilera - wtedy będziesz się martwić.

0

Pokaż ten swój benchmark. Akurat alokacja ma sporą szansę być szybsza w C#. Wywoływanie metod to w gruncie rzeczy będzie to samo.

Znalazłem coś, co testowałem kilka lat temu. Przy tych testach różnica dochodzi od 3 do prawie 4x na korzyść native. Trudno mi w tej chwili powiedzieć o tych 8-10 razach ale z pewnością jak robiłem podobne testy tak wychodziło. Z tego co pamiętam to robiłem jeszcze bardziej złożone przykłady. Przy czym te 10x to zapewne chodziło o c#.
Oczywiście zdaję sobie sprawę z tego, że różnica szybkości mocno jest uzależniona od zadania. Ale akurat w moim przypadku ogrom obliczeń przypada na tworzenie i zwalnianie obiektów oraz dostępie do ich metod. Zanim zabrałem się do pisania "przetrzepałem" sieć w poszukiwaniu podobnych opinii i rzeczywiście one były niejednoznaczne. Postanowiłem więc sam to sprawdzić i zrobić testy. Różnica dla moich zastosowań była porażająca dlatego zdecydowałem się na system łączony - jak chcę napisać łatwo i szybko to piszę w c#. Jak chcę bardzo szybkich obliczeń - przerzucam kod do native i dzięki "opakowywaniu" go za pomocą zarządzanego C++, z poziomu c# korzystam z tych obiektów bardzo wygodnie.

---------Kod zarządzany--------------

 // SpeedTest_CppManaged.cpp : main project file.


#include "stdafx.h"
#include <iostream>
#include <tchar.h>
#include <windows.h>

using namespace System;

ref class cLine{
public:
	float X1;
	float X2;
};

ref class cShape{
public:
	int a;
	cLine Line;
};

int CreateObjects(int xVal){

	cShape pShape;

	pShape.Line.X1 = xVal;
	pShape.Line.X2 = xVal * 2;
				
	return pShape.Line.X1 + pShape.Line.X2 / xVal;

}

int main(array<System::String ^> ^args)
{
  int pVal, pValA = 0;
  int pStart, pEnd;

  printf("%s\n", "Starting ...");
	
	pStart = GetTickCount();

  for (int i = 0; i < 1000000000; i++)
	{
		pValA += CreateObjects(i);
	}
	
  pEnd = GetTickCount();

	pVal = pEnd - pStart;
	
  printf("%d\n", pVal);
	printf("%d\n", pValA);

  printf("%s", "Press Enter to Continue");

  getchar();

  return 0;

}

---------Kod natywny--------------

 
// SpeedTest_Cpp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <tchar.h>
#include <windows.h>


using namespace std;


class cLine{
public:
	float X1;
	float X2;
};

class cShape{
public:
	int a;
	cLine Line;
};

int CreateObjects(int xVal){

	cShape pShape;
	int pVal;

	pShape.Line.X1 = xVal;
	pShape.Line.X2 = xVal * 2;

	pVal = pShape.Line.X1 + pShape.Line.X2 / xVal;

	return pVal;

}

int _tmain(int argc, _TCHAR* argv[])
{

  int pVal, pValA = 0;
  int pStart, pEnd;

  printf("%s\n", "Starting ...");

  pStart = GetTickCount();

  for (int i = 0; i < 1000000000; i++)
  {
    pValA += CreateObjects(i);
  }


  pEnd = GetTickCount();

  pVal = pEnd - pStart;

  printf("%d\n", pVal);
  printf("%d\n", pValA);

  printf("%s", "Press Enter to Continue");

  getchar();

  return 0;

}


1

Ciężko mówić tutaj o miarodajnym porównaniu, bo pomimo tego, że kod wygląda dość podobnie to mechanika za nim jest trochę inna. W pierwszym przypadku masz faktyczny obiekt (na stosie), wywołanie konstruktora. W drugim kompilator to wszystko wywali, bo z jego perspektywy są tam tylko dwie zmienne lokalne.

Nie można więc tutaj porównywać szybkości alokacji, wywoływania metod, bo nie ma jej ani w jednym, ani w drugim przykładzie ;). Nie ma też na przykład destruktorów, a tutaj też sprawa diametralnie się różni, bo wywołanie tego w C++ jest deterministyczne, a domyślnie w .NET nie (i przykładowo w C++ wyjście sporawego wektora obiektów ze scope może przydusić cały program).

Szybkość "obiektów" jest ciężka do porównania i na pewno nie zrobisz tego w dziesięciu linijkach.

0

No to świadczy tylko o tym, że .NET ma słabe optymalizacje. JVMka (np ta od Oracle) potrafi zinlineować wywołania konstruktorów jak i wiele innych sztuczek. Zresztą już pokazywałem przykład kiedyś: Dlaczego foreach jest gorsze od for (beta)
Kompilatory C++ też potrafią powycinać tworzenie obiektów itd Jeśli .NET nie potrafi, to to ból .NETa

0
Rev napisał(a):

Wykonywałem też testy z wykorzystaniem zarządzanego c++ i czas wykonywania kodu jest wtedy zbliżony do C#.

Bo zarządzany C++ jest kompilowany do IL - tak samo jak C#.

Tym można sterować za pomocą dyrektyw

#pragma managed
#pragma unmanaged

poza tym nawet w ramach jednego projektu w Visual Studio można wybierać, które pliki .cpp mają być kompilowane jako natywne C++ a które jako C++/CLI.

Jest jeszcze problem zwany "double thunking" objawiający się m.in. przy metodach wirtualnych. Pomaga użycie konwencji wywołania __clrcall.

1 użytkowników online, w tym zalogowanych: 0, gości: 1