Почему различие в производительности между C# (вполне немного медленнее) и Win32/C?

REST-сервер + тяжелый JavaScript-клиент был принципом, которому я следовал в своей недавней работе.

REST-сервер был реализован в node.js + Express + MongoDB (очень хорошая производительность записи) + Mongoose ODM (отлично для моделирования данных, включая проверки) + CoffeeScript (я бы сейчас использовал ES2015 вместо этого), который хорошо сработал для меня. Node.js может быть относительно молодым по сравнению с другими возможными серверными технологиями, но это позволило мне написать надежный API с интегрированными платежами.

Я использовал Ember.js в качестве среды JavaScript, и большая часть логики приложения была выполнена в браузере. Я использовал SASS (в частности, SCSS) для предварительной обработки CSS.

Ember - зрелая структура, поддерживаемая сильным сообществом. Это очень мощный фреймворк, в котором в последнее время проводится много работы, ориентированной на производительность, например, новый движок рендеринга Glimmer (по мотивам React).

Ember Core Team находится в процессе разработки FastBoot , который позволит вам выполнить вашу логику Ember JavaScript на стороне сервера (в частности, node.js) и отправлять предварительно отрендеренный HTML-код вашего приложения (что будет обычно запускается в браузере) пользователю. Это здорово для SEO и пользовательского опыта, так как он не ждет так долго, пока страница не появится.

Ember CLI - это отличный инструмент, который помогает вам организовать ваш код, и он хорошо масштабировался с ростом кодовой базы. Ember также имеет свою собственную аддонную экосистему, и вы можете выбирать из множества Ember Addons . Вы можете легко взять Bootstrap (в моем случае) или Foundation и добавить его в свое приложение.

Чтобы не обслуживать все через Express, я решил использовать nginx для обслуживания изображений и клиент с большим количеством JavaScript. Использование прокси-сервера nginx было полезно в моем случае:

upstream app_appName.com {
  # replace 0.0.0.0 with your IP address and 1000 with your port of node HTTP server
  server 0.0.0.0:1000;
  keepalive 8;
}

server {
  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  client_max_body_size 32M;

  access_log  /var/log/nginx/appName.access.log;
  error_log  /var/log/nginx/appName.error.log;

  server_name appName.com appName;

  location / {
     # frontend assets path
     root /var/www/html;
     index index.html;

     # to handle Ember routing
     try_files $uri $uri/ /index.html?/$request_uri;
  }

  location /i/ {
    alias /var/i/img/;
  }

  location /api/v1/ {
    proxy_pass  http://app_appName.com;

    proxy_next_upstream error timeout invalid_header http_500 http_502
http_503 http_504;
    proxy_redirect off;
    proxy_buffering off;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Pro: Мне нравится разделение API & amp; клиент. Умные люди говорят, что это путь. Великолепно в теории. Кажется передовым и захватывающим.

Я могу сказать, что это также здорово на практике. Еще одним преимуществом разделения REST API является то, что вы можете использовать его позже для других приложений. В идеальном мире вы должны иметь возможность использовать один и тот же API REST не только для веб-страниц, но и для мобильных приложений, если решите написать его.

Против: не так много прецедентов. Не много примеров этого сделано хорошо. Публичные примеры (twitter.com) чувствуют себя вялыми даже отказываются от этого подхода.

Теперь все выглядит иначе. Есть много примеров использования REST API + много клиентов, использующих его.

16
задан Greg D 29 June 2009 в 20:07
поделиться

7 ответов

Я считаю, что ваша основная проблема в этом коде будет заключаться в проверке границ ваших массивов.

Если вы переключитесь на небезопасный код в C # и используете математику указателя, вы сможете для достижения того же (или потенциально более быстрого) кода.

Эта же проблема ранее подробно обсуждалась в этом вопросе .

18
ответ дан 30 November 2019 в 16:05
поделиться

Я думаю, вы видите результаты проверки границ массивов. Вы можете избежать проверки границ, используя небезопасный код.

Я считаю, что JITer может распознавать шаблоны, такие как циклы for, которые идут вверх до array.Length, и избегать проверки границ, но не похоже, что ваш код может это использовать.

13
ответ дан 30 November 2019 в 16:05
поделиться

Как уже говорили другие, одним из аспектов является проверка границ. В вашем коде также есть некоторая избыточность с точки зрения доступа к массиву. Мне удалось несколько улучшить производительность, изменив внутренний блок на:

int tmp1 = array1[i];
int tmp2 = array2[k];
if (tmp1 == tmp2)
{
    calc = calc - array2[i] + array1[k];
}
else
{
    calc = calc + tmp1 - tmp2;
}

Это изменение снизило общее время с ~ 8,8 до ~ 5 с.

6
ответ дан 30 November 2019 в 16:05
поделиться

Ради удовольствия, я попытался создать это на C # в Visual Studio 2010 и взглянул на разборку JITed:

                    else 
                        calc = calc + array1[i] - array2[k];
000000cf  mov         eax,dword ptr [ebp-10h] 
000000d2  add         eax,dword ptr [ebp-14h] 
000000d5  sub         eax,edx 
000000d7  mov         dword ptr [ebp-10h],eax 

Они внесли ряд улучшений в джиттер в 4.0 версии CLR.

4
ответ дан 30 November 2019 в 16:05
поделиться

Если критический путь производительности вашего приложения полностью состоит из обработки неконтролируемых массивов, я бы посоветовал вам не переписывать его на C #.

Но тогда, если ваше приложение уже нормально работает на языке X , Я бы посоветовал вам не переписывать его на языке Y.

Чего вы хотите добиться от перезаписи? По крайней мере, серьезно подумайте о смешанном языковом решении, используя уже отлаженный код C для высокопроизводительных разделов и используя C # для получения приятного пользовательского интерфейса или удобной интеграции с новейшими богатыми библиотеками .NET.

A более подробный ответ на возможно связанную тему.

1
ответ дан 30 November 2019 в 16:05
поделиться

C # выполняет проверку границ

при выполнении расчетной части в небезопасном коде C #. Работает ли она так же хорошо, как собственная реализация?

2
ответ дан 30 November 2019 в 16:05
поделиться

Я уверен, что оптимизация для C отличается от C #. Также вы должны ожидать, по крайней мере, небольшого снижения производительности. .NET добавляет еще один уровень к приложению с помощью фреймворка.

Компромисс - более быстрая разработка, огромные библиотеки и функции при (что должно быть) небольшой скорости.

0
ответ дан 30 November 2019 в 16:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: