Я волновался по поводу скорости C#, когда она имеет дело с тяжелыми вычислениями, когда необходимо использовать необработанную мощность ЦП.
Я всегда думал, что C++ намного быстрее, чем C# когда дело доходит до вычислений. Таким образом, я сделал некоторые быстрые тесты. Первый тест вычисляет простые числа <целое число n, второй тест вычисляет некоторые pandigital числа. Идея для второго теста прибывает отсюда: Числа Pandigital
C# главное вычисление:
using System;
using System.Diagnostics;
class Program
{
static int primes(int n)
{
uint i, j;
int countprimes = 0;
for (i = 1; i <= n; i++)
{
bool isprime = true;
for (j = 2; j <= Math.Sqrt(i); j++)
if ((i % j) == 0)
{
isprime = false;
break;
}
if (isprime) countprimes++;
}
return countprimes;
}
static void Main(string[] args)
{
int n = int.Parse(Console.ReadLine());
Stopwatch sw = new Stopwatch();
sw.Start();
int res = primes(n);
sw.Stop();
Console.WriteLine("I found {0} prime numbers between 0 and {1} in {2} msecs.", res, n, sw.ElapsedMilliseconds);
Console.ReadKey();
}
}
Вариант C++:
#include
#include
#include
int primes(unsigned long n) {
unsigned long i, j;
int countprimes = 0;
for(i = 1; i <= n; i++) {
int isprime = 1;
for(j = 2; j < sqrt((float)i); j++)
if(!(i%j)) {
isprime = 0;
break;
}
countprimes+= isprime;
}
return countprimes;
}
int main() {
int n, res;
cin>>n;
unsigned int start = clock();
res = primes(n);
int tprime = clock() - start;
cout<<"\nI found "<
Когда я запустил тест, пытающийся найти начала <чем 100 000, вариант C# законченный через 0,409 секунды и вариант C++ за 0,614 секунды. Когда я выполнил их для 1 000 000 C#, законченных через 6,039 секунд и C++ приблизительно через 12,987 секунд.
Pandigital тестируют в C#:
using System;
using System.Diagnostics;
class Program
{
static bool IsPandigital(int n)
{
int digits = 0; int count = 0; int tmp;
for (; n > 0; n /= 10, ++count)
{
if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1)))
return false;
}
return digits == (1 << count) - 1;
}
static void Main()
{
int pans = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 123456789; i++)
{
if (IsPandigital(i))
{
pans++;
}
}
sw.Stop();
Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds);
Console.ReadKey();
}
}
Pandigital тестируют в C++:
#include
#include
using namespace std;
int IsPandigital(int n)
{
int digits = 0; int count = 0; int tmp;
for (; n > 0; n /= 10, ++count)
{
if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1)))
return 0;
}
return digits == (1 << count) - 1;
}
int main() {
int pans = 0;
unsigned int start = clock();
for (int i = 1; i <= 123456789; i++)
{
if (IsPandigital(i))
{
pans++;
}
}
int ptime = clock() - start;
cout<<"\nPans:"<
Вариант C# работает через 29,906 секунд и C++ приблизительно через 36,298 секунд.
Я не коснулся никаких переключателей компилятора, и и C# и программы C++ были скомпилированы с параметрами отладки. Прежде чем я попытался запустить тест, я волновался, что C# отстанет далеко позади C++, но теперь кажется, что существует довольно большое различие в скорости в пользе C#.
Кто-либо может объяснить это? C# является jitted, и C++ компилируется собственный компонент, таким образом, нормально, что C++ будет быстрее, чем вариант C#.
Спасибо за ответы!
Я имею, восстановил все тесты для конфигурации Выпуска.
Сначала протестируйте (простые числа)
C# (числа <100,0000): 0,189 секунды C++ (числа <100,0000): 0,036 секунды
C# (числа <1,000,000): 5 300 секунд C++ (числа <1,000,000): 1,166 секунды
Второй тест (pandigital числа):
C#: 21,224 секунды C++: 4,104 секунды
Так, все изменилось, теперь C++ намного быстрее. Моя ошибка состоит в том, что я имею, запустил тест для Настройки отладочного процесса. Я могу видеть некоторое улучшение скорости, если я выполнил исполняемые файлы C# через ngen?
Причина я пытался сравнить C# и C++, состоит в том, потому что я знаю некоторые основы обоих, и я хотел изучить API, имеющий дело с GUI. Я думал, что WPF хорош поэтому, учитывая, что я нацелен на рабочий стол, я хотел видеть, может ли C# обеспечить достаточно скорости и производительности когда дело доходит до использования чистая мощность ЦП для вычислений различных вычислений (файл archivers, криптография, кодеки и т.д.). Но кажется, что печально C# не может идти в ногу с C++ когда дело доходит до скорости.
Так, я предполагаю, что навсегда застряну с этим Сложным вопросом вопроса на WPF, Win32, MFC, и я буду более новая находка подходящий API.
Почему вы предполагаете, что jit-код медленнее, чем собственный код? Единственным штрафом за скорость будет фактическое дрожание, которое происходит только один раз (вообще говоря). Учитывая программу с продолжительностью работы 30 секунд, мы говорим о незначительной части общей стоимости.
Думаю, вы можете спутать jit-код с интерпретируемым кодом, который компилируется построчно. Между ними есть довольно значительная разница.
Как указывали другие, вам также необходимо запустить это в режиме выпуска; В режиме отладки отключает большинство оптимизаций, поэтому обе версии будут работать медленнее, чем должны быть (но на разную величину).
Изменить - я должен указать еще на одну вещь, а именно, что эта строка:
for (j = 2; j <= Math.Sqrt(i); j++)
невероятно неэффективна и может помешать тестированию. Вы должны вычислять Math.Sqrt (i)
вне внутреннего цикла. Возможно, это замедлит обе версии на эквивалентную величину, но я не уверен, что разные компиляторы будут выполнять разные оптимизации.
Во-первых, никогда не выполняйте такие тесты в режиме отладки. Чтобы получить значимые числа, всегда используйте режим выпуска.
JIT имеет то преимущество, что знает платформу, на которой он работает, в то время как предварительно скомпилированный код может быть неоптимальным для платформы, на которой он работает.
Вам необходимо скомпилировать C ++ в режиме выпуска и включить оптимизацию, чтобы получить желаемые результаты производительности.
генератор простых чисел в C ++ неверен
i ^ (1/2) == i xor 0
^ - побитовый оператор xor а / - целочисленное деление.
1-е изменение , это правильно, но неэффективно: Поскольку i xor 0 == i, сито останавливается не на sqrt (i), а на i.
2-е изменение:
Просеивание можно сделать немного более эффективным. (Вам нужно только вычислить sqrt (n)). Вот как я реализовал Сито Эратосфена для собственного использования (хотя это и в C99):
void sieve(const int n, unsigned char* primes)
{
memset(primes, 1, (n+1) * sizeof(unsigned char));
// sieve of eratosthenes
primes[0] = primes[1] = 0;
int m = floor(sqrt(n));
for (int i = 2; i <= m; i++)
if (primes[i]) // no need to remove multiples of i if it is not prime
for (int j = i; j <= (n/i); j++)
primes[i*j] = 0;
}
Это занимает намного больше времени, потому что алгоритм неправильный.
for(j = 2; j < (i^(1/2)); j++)
это то же самое, что
for(j = 2; j < (i^0); j++)
это то же самое, что
for(j = 2; j < i; j++)
i намного больше, чем sqrt(i). Если смотреть только на время работы, то оно на порядок больше, чем должно быть в реализации на C++.
Также, как и все остальные, я не думаю, что имеет смысл проводить тестирование производительности в режиме отладки.
Перекомпилируйте программу C ++ с включенной полной оптимизацией и повторно запустите тесты. C # jit оптимизирует код при его jit, поэтому вы сравнили оптимизированный код C # /. NET с неоптимизированным C ++.
Оба теста недействительны, потому что вы компилировали без оптимизаций.
Первый тест не имеет смысла даже как сравнение неоптимизированного поведения из-за ошибки в вашем коде; Math.Sqrt(i)
возвращает квадратный корень из i, i^(1/2)
возвращает i - так что C++ делает гораздо больше работы, чем C#.
В целом, это не очень полезное занятие - вы пытаетесь создать синтетический эталон, который практически не имеет отношения к реальному использованию.
ребята, прежде чем сравнивать скорость работы программ друг с другом, пожалуйста, потрудитесь прочитать несколько статей об инструкциях процессора, ассемблере, управлении кэшем и т.д. А автор просто до смешного забавный приятель. Проверка производительности отладочной сборки.
Billy O'Neal - в чем разница между выделением большого буфера и использованием только небольшой его части и использованием динамически выделяемой вещи, такой как вектор, выражаясь низким языком? Как только большой буфер был выделен - никто не беспокоится о неиспользуемом материале. Никаких дополнительных операций поддержки не требуется. В то время как для динамических вещей, таких как вектор, требуется постоянная проверка границ памяти, чтобы не выходить за ее пределы. Помните, что программисты на C++ не только ленивы (что очень верно, я признаю), но и умны.
Как насчет этого:
for(sqrti = 1; sqrti <= 11112; sqrti++) {
int nexti = (1+sqrti)*(1+sqrti)
for (i = sqrti*sqrti; i < nexti; i++)
{
int isprime = 1;
for(j = 2; j < sqrti; j++)
if(!(i%j)) {
isprime = 0;
break;
}
}
} countprimes+= isprime; }
Это устойчивый миф, что JIT-компилятор в управляемом коде генерирует машинный код, который намного менее эффективен, чем тот, который генерируется компилятором C/C++. Управляемый код обычно выигрывает в управлении памятью и математике с плавающей запятой, C/C++ обычно выигрывает, когда оптимизатор кода может потратить гораздо больше времени на оптимизацию кода. В целом, управляемый код составляет около 80%, но это полностью зависит от тех 10% кода, где программа проводит 90% своего времени.
Ваш тест этого не покажет, вы не включили оптимизатор, и оптимизировать особо нечего.