Как стать автором
Обновить

Комментарии 75

Ожидал увидеть хотя бы парочку опровержений существующих тестов, с применением описанных знаний…
Тут я ничего не опровергаю. Просто указал на сложность реального измерения в реальных проектах, которые могут очень сильно отличаться от тестовых результатов, при чем как положительную, так и в отрицательную сторону.
а я ожидал графиков сравнения скорости, вы ведь привели туманный пример Delphi vs Java, что мешает сделать стандартных 10 функций там и там сравнить выполнение на 15 -20 к вызовов?

такую же статью может наклепать каждый кто прочитал доки и прикинул на пальцах, что к чему
Сожалею что не оправдал ваших ожиданий, но меня уже от этих графиков уже тошнит. Я их навидался достаточно, что бы перестать на них обращать внимания и вам не советую. Синтетические тесты на яве это фикция, они абсолютно ничего не показывают, потому что пропускная способность java кода не является константой! В этом и есть суть того, что я хочу сказать. Это одна из тех причин по которой обычную JVM не используют в системах реального времени.
RTSJ позволяет писать программы на Java для систем реального времени.

Кстати марсоходы Spirit и Opportunity работали под управлением Java программы.
Поэтому я сделал ремарку «обычная JVM». И RTSJ от SUN платная, и работает только на линуксе и солярисе с ядрами реального времени. Но кроме самой JVM для обеспечения реального времени нужно очень внимательно использовать рекомендации при программировании и использовать специальные библиотеки. Что делает код тяжело переносимым между разными JVM. Хотя для таких систем это не актуально. Java это вообще огромная вселенная технологий, чего там только нет. :)
А я-то думаю: «Почему мы там жизнь так и не нашли?».
Потому что плохо искали, ясен пень :-)
НЛО прилетело и опубликовало эту надпись здесь
я так понял, что статья дл начинающих? или данный факт можно постигнуть только после просветления?

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

про графики я просто пропущу реплику.

а что такое собственно «пропускная способность java кода»? от чего она зависит?
Извините, я пытался излагать мысли как можно проще. Для специалистов есть документация.

>>а что такое собственно «пропускная способность java кода»? от чего она зависит?

Это термин из проектирования систем реального времени. Производительность в режиме реального времени отличается от стандартной производительности, которая, как правило, характеризуется пропускной способностью, т.е. числом задач или инструкций, выполняемых в единицу времени. Но из-за того что это в Java этот параметр невероятно изменяется, он начинает влиять и при дектопном программировании, вызывая высокую латентность кода.

К примеру оптимизация JIT хорошо иллюстрируется на примере специализации копирования массивов. Для часто выполняющегося метода компилятор JIT может собрать статистику о длине массива в целях выяснения, массивы какой длины встречаются наиболее часто. Например, после накопления достаточной статистики он может сделать вывод, что длина практически всегда равна 12. После этого компилятор способен сгенерировать код метода arraycopy, который будет копировать 12 байтов способом, максимально эффективным для данного типа процессора. Кроме того, компилятор добавит проверку длины массива, чтобы новый код выполнялся только в том случае, когда длина равна 12. В противном случае будет выполняться менее эффективный код, который способен обрабатывать массивы любой длины. Если в большинстве случаев выполняется специализированный код, то именно он будет определять среднюю латентность операции. При этом операции копирования массивов другой длины будут выполняться значительно дольше.
пожалуй стоило написать про это статью.
мерси за наочность
Возможно напишу, я люблю разбирать в архитектуре таких сложных систем. Но это на столько специфическая и сложная тема, что я пока не решусь за неё взяться. Нужно самому её изучить поподробнее.

Но я надеюсь, что в скором будущем в России таки начнется бум роботостроения как в Японии и тогда эта тема станет как никогда актуальной. :)
Больше философская статья получилась :) А последний абзац даже настроение приподнял. Прям так и захотелось забить на обед и продолжить написание кода на любимом языке, чтобы снова и снова ощущать эти волны радости :)
Ради этого и писалось, а то так надоели бесконечные холивары, что хуже, а что лучше. Лучше то, что приносит радость. А вообще писалось для начинающих разработчиков, которых статистика работы Java пугает чаще всего. Поэтому ничего конкретного нет. Просто в СНГ сообщество Java довольно небольшое и многие тонкости, начинающий разработчик может узнать только из документации или англоязычных форумов. А так качество переводов книг у нас ужасное, то на них надежды нет. Специалистам нужно больше общаться друг с другом, это один из лучших способов повышения квалификации.
НЛО прилетело и опубликовало эту надпись здесь
Конструктивный холивар, это способ познать истину, а бессмысленная полемика это всего лишь способ повысить свое ЧСВ.

Традиции интернет-холиваров уходят своими корнями в древнегреческую дискуссионную философию и средневековую схоластику. Это не только оттачивание ума и языка, но и обучение навыкам конструктивного диалога, аналитического мышления, памяти и терпения. В таких дискуссиях тролли, в виду интеллектуально ограниченности, участвовать не могут, а вот загадить дискуссию могут. Бороться бесполезно, а что бы просто игнорировать нужно много терпения.
хорошо сказано!
НЛО прилетело и опубликовало эту надпись здесь
Напишите сапера :-) полегчает
НЛО прилетело и опубликовало эту надпись здесь
ну и чушь вы несете
Ну зачем так категорично. Нужно было сказать так — «Вы сильно заблуждаетесь глубокоуважаемый коллега. Java специально адаптировалась под выконагруженные и масштабируемые серверные приложения. Поэтому производительность Java на серверах полностью сопоставима с C/C++, но благодаря гибкой масштабируемости и интероперабельности она является более предпочтительным инструментом для создания корпоративных систем.»
НЛО прилетело и опубликовало эту надпись здесь
не совсем понял вашей просьбы, но таки похоже, что вы мыслите только в рамках построения оперденей. отличные от оперденей программы далеко не всегда пишутся на плюсах, как вы, очевидно, думаете.

посмотрите на тот же АСУТП например, или на телеком в части взаимодействия с железом. какой там нахер дизайн?

очнитесь, уважаемый.
Да глупость вы говорите. Возьмем банально ворд 2010. Открытие doc-файла (впрочем как и docx), большего нескольких мегабайт (без картинок) — довольно заметно. В свое время я эксперементировал и файл в 30 мб чистого текста ворд 2007 так и не открыл — завис.

При этом ворд 97 мгновенно загружает любой doc-файл.

Да, я заметил, что похоже новые ворды грузят весь файл целиком ибо памяти много, а 97 при перелистывании немного задумывается, но это не отменяет того, что меня как пользователя бесит время загрузки.

Именно поэтому офис 97 портабл все еще популярен (хотя с приходом docx все меньше).
Вообще-то docx надо сначала распаковать, чтобы открыть. Это же zip!
Вот сделал docx файлик из текста нескольких комментариев на 1300 страниц и 500000+ слов:
image
Не поверите: мой текущий проект — обработка docx-файла. Как он устроен я прекрасно знаю.
Но это не отменяет того, что раззиповка документа при открытии — минимальная вводная фаза, обработка XML обходится КУДА дороже.
Это потому, что многие парсеры используют пресловутую объектную модель при обработке XML и мусорят в памяти бесконечным числом объектов… а нужно, то всего лишь старое доброе побайтное потоковое чтение… Хотя в odf принцип точно такой же, но под линуксом проблем с чтением больших доков замечено не было. Возможно они плевали на ооп и реализовали парсер на си. :)
Важно не на чем, а как :-)
В текстовом парсинге я тоже склоняюсь к потоковому побайтному чтению, но ООП тоже использую — очень уж легко подменять обработчики в зависимости от контекста ) накладные расходы не такие уж большие (не более 50 служебных объектов-парсеров для случая XML).
В наказание десять тысяч раз напишите на доске «Java»!

У статьи замечательные по энергетике последние два абзаца.
При таком раскладке сравнение производительности АОТ-компилятора Java с компилятором тех же плюсов будет корректнее.
Я изучал этот вопрос. И ответа не нашел. В оригинальной JVM HotSpot этого к сожалению её нет. Есть несколько сторонних реализации АОТ-компилятора для Java. Но у всех есть недостатки. Бесплатный gnu/gcj — практичеки умер. Немецкий exe4j, только под виндовс и платный, а вот российский Excelsior JET может создавать код под Linux и Windows, но на столько же, на сколько он великолепен, на столько невероятно дорог. Его стоимость вызывает шок. Возможность АОТ компиляции есть в некоторых JVM от IBM, но они специализированны исключительно под сервера и продукты IBM. Так что с АОТ компиляторами в Java все довольно печально.
Понимаю, что это подходит не всем, но для некоммерческих проектов несложно получить бесплатную лицензию, а на попробовать хватит и 30-ти дневного триала. Так что я не сказал бы, что все совсем печально.
Пробовал. Но давненько, понравилось. Но СПО проектами на яве не занимаюсь. Ява больше для бизнеса требуется. Так что при прочих равных, для разовых проектов проще использовать, что-то более тривиальное, — c++/lazarus/python. Хотя я когда-то читал, что можно получить бесплатную лицензию для ВУЗа. Если это возможно, то я бы с удовольствием дал своим студентам вдоволь поиграться с нативной явой. Ближе к осени попробую обратиться. Лично меня полностью устраивает настройка производительности JVM.
Скорее всего это возможно, и думаю студентам полезно будет для расширения кругозора :)
Я думаю, все разговоры о производительности Явы на десктопе банально опровергаются временем загрузки/инициализации VM, загрузки кусков 50-мегабайтного rt.jar и скоростью загрузки классов (низкая, так как классы раскиданы по сотням мелких файлов или архивов). С такой неудачной архитектурой Ява никогда близко к Си/Си++ не приблизится.

Плюс медленный сборшик мусора.

Не говоря о том, что Ява программа используют в среднем больше RAM, что увеличивает их вероятность оказаться в свопе, что тоже сильно снижает производительность и самой ява-программы, и всех остальных запущенных одновременно программ.

А еще у Явы есть проблемы необходимости поддержки старого, плохого legacy кода.
> С такой неудачной архитектурой

спасибо, что вы об этом сообщили. а то никто ни в Sun с их Явой, ни в Microsoft с их C# об этом не знает.
>> Плюс медленный сборшик мусора.

нормальный.

>> Не говоря о том, что Ява программа используют в среднем больше RAM

в среднем больше чем что?

>> А еще у Явы есть проблемы необходимости поддержки старого, плохого legacy кода.

прочёл как «есть много проверенных и отлаженных библиотек на все случае жизни».

я сам на плюсах пишу, есличо
>>А еще у Явы есть проблемы необходимости поддержки старого, плохого legacy кода.
Если бы у явы не было бы этой проблемы, то это бы стало огромной проблемой программистов. Если бы нам приходилось бы каждые 3 года переписывать код, то стоимость разработки стала бы занебесной. А тот факт что код с 1999 года можно использовать в новых проектах, используя новые возможности не лишаясь старых, это жирный экономический плюс, перевешивающий все остальные минусы.

Ну а по остальным парметрам, JVM настраивается руками, оптимизация класслоадер и сборщики мусора могут быть оптимизированы под приложение. В статье я дела упор на то, что делает JVM по умолчанию без участия программиста. Возможности тюнинга Java это совершенно отдельная история. Я её лишь слегка коснулся.
В качестве курсовика в последнем семестре я писал движок регулярных выражений, аналогичный google re2, только на Java. Сначала скорость отличалась в 10 раз в сравнении с плюсовым re2 и я здорово расстроился. Однако нормально допилив алгоритм (кэширование-кэширование-кэширование!), аналогично re2 и убрав создание огромного числа объектов, заменив реинициализацией имеющихся получил проигрыш в 1,5 раза всего (150 против 250 мб/с).

Уверен, что можно было довести почти до плюсовых скоростей, хотя уже не «бесплатно», а используя оптимизации и учитывая работу JVM.

PS: Одним из важных выводов по курсовику стало то, что Java проигрывает плюсам не в 10 раз, а в 2, если писать на ней НЕ как на си (то есть как привык), а учитывая специфику.
Может и плюсовики могли бы дальше что-нибудь ускорить
у плюсовиков довольно много ограничений которые им помешают, а вот у сишников полная свобода для оптимизации, и программы написанные на си самые быстрые, но си это фактически ассемблер второго порядка, что бы на нем писать нужно иметь ооочень много опыта. А такие специалисты это штучные товар. А мировой индустрии нужны легионы программистов.

Читал статью еще советского времени, начала 80х, что к 2020 году придется посадить за программирование практически 80% трудоспособного населения чтобы удовлетворить потребности индустрии, и я так думаю что они не сильно ошиблись в прогнозах.
Я все таки не вполне понимаю где у плюсов может быть просад по сравнению с С, единственная разница на мой взгляд в косвенных вызовах функций через таблицу виртуальный функций. Еще там где включена обработка исключений или RTTI может быть дополнительный оверхед по сравнению с C.

> Читал статью еще советского времени, начала 80х, что к 2020 году придется посадить за программирование практически 80%

Я читал книгу еще советсткого времени где говорилось об ошибочности такого рода интерполяций. Вроде как аналогичные расчеты по лошадям в Лондоне предсказывали что в 20-м веке город будет полностью завален метровым слоем навоза. Бурный рост на начальном этапе развития нет смысла так проецировать в будущее.

При том что для армии «индусов» пишущих интерпрайз более подходит Java тут наверное нельзя не согласится.
Первое что пришло в голову: исключения — нужно ставить обработчики, чтобы по стеку возвращаться.
Там больше проблема не с обработчиках, а в собирании stack trace при создании объекта — очень дорогая операция.
Полезно, спасибо!
Большое количество реальных сравнений производительности Java написано людьми, у которых есть только начальные представления о ней. К сожалению, в этом случае легко получаются результаты, которые свидетельсвуют о ее низкой производительности. Чаще всего это происходит из-за отсутствия «прогрева» приложения перед тестированием (чтобы JIT заработал), плюс, незнание об автобоксинге примитивов в коллекциях (в джаве все примитивы преобразуются в объекты перед помещением в коллекции).

Однако во многих случаях производительность джавы может держаться на уровне C++. Лучшей статьей на эту тему, наверное, является Java vs. C Performance… Again от одного из прошлых сотрудников Sun и разработчика серверной версии JIT-компилятора, Cliff Click.
Кстати, провел маленький тест, который, в общем подтверждает текст статьи:
public class JavaJITtest {

public static final int MAX_CNT = 10000;

public static void main(String[] args) {

double sum = 0;

long ts = System.nanoTime();
for (int ctr = 0; ctr<MAX_CNT; ctr++ ) {
// sum += getSum(ctr); // Variant A
// sum += ctr + (MAX_CNT-ctr); // Variant B
}
long te = System.nanoTime();
te = (te-ts)/1000;
System.out.println("Time is: "+te+"uS");
System.out.println("Result: "+sum);

}

private static double getSum(int ctr) {
return ctr + (MAX_CNT-ctr);
}
}


Тестировал на winxp, java практически свежая:
java version «1.6.0_25»
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) Client VM (build 20.0-b11, mixed mode, sharing)

Нужно раскомментировать одну из строчек, Variant A или Variant B
Как вы думаете, какой вариант работает быстрее, если не трогать -XX:CompileThreshold?
А если задать -XX:CompileThreshold ну скажем 20000, или 100?
Если для варианта B — разницы нет практически никакой, то для варианта A — где та же формула выделена в функцию, скорость значительно отличается, так, если не трогать -XX:CompileThreshold, для варианта A получаем выигрыш по скорости на ~50%.

А на Спарке (Sunfire-V240)
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) Server VM (build 20.0-b11, mixed mode)
С ключиком -client такого эффекта не получилось. Вариант без вызова функции, работает быстрее. При -XX:CompileThreshold=100 быстродействие обоих вариантов практически сравнялось. Увеличение количества итераций в 10 раз, тоже к заметной разнице не привело. В 64-битном и серверном режиме VM, вариант с вызовом функции всегда проигрывает. Видать, это особенность архитектуры спарков.
На spec.org документация к java-benchmark'ам содержит подробные описания того, как нужно проводить замеры, чтобы получать достоверные цифры. Помимо этого нужно использовать мат. статы для анализа полученных данных: доверительные интервалы, разброс результатов, вычисление минимального числа необходимых запусков и т.п.

В JRockit'е вообще отсутствует интерпертатор, JRockit работает по схеме:

1. Каждый вызываемый метод сразу компилируется в машинный код.
2. Скомпилированный код мониторится и ищутся хотспоты.
3. Хотспоты оптимизируются.

НЛО прилетело и опубликовало эту надпись здесь
>> 1. Каждый вызываемый метод сразу компилируется в машинный код.

В HotSpot такое поведение имитировать с помощью XX:CompileThreshold=1 Если честно не знаю как JRockit при этом обходит дикие лаги при старте. Хотя JRockit используется исключительно на серверах, так что там этого никто не заметит. Пункт 2 и 3, такие же как и в HotSpot. Хотя могут использоваться более быстрые алгоритмы, но принцип такой же. Насколько я знаю JRockit полностью написана на Си и некоторые системные библиотеки были переписаны с Java на Си, чем они и добились повышения производительности. Если бы HotSpot умела бы кэшировать код созданный JIT компилятором, и статистику, между сессиями запуска, то отличий бы вообще не было. Но к сожалению не смотря на все мольбы, JIT кэширования нет и не скоро появится, если вообще появится.
Думаю за счет того, что используется минимум/или отсутствие оптимизаций. Компиляцию в машинный код без оптимизаций можно сделать очень быстро. Одна из самых сложных задач для JIT — это алокация регистров, которая как известно NP-задача.
Забавно, что в HotSpot интерпретатор генерируемый, его машинный код создается при старте JVM.
Да, кэширования JIT кода нет, но есть Class data sharing (CDS), которое позволяет уменьшить время запуска приложения за счет шаринга мета-данных между запущенными JVM-ками.
НЛО прилетело и опубликовало эту надпись здесь
Я вот такое всё хотел написать, точнее спросить. Хотелось бы статистику по десктопным приложениям, как по мне, так тот же PhpStorm конечно побыстрее Эклипса и ему подобных, но на порядки медленнее NuSphere PhpED (он вроде на сях), при этом мне импонирует Java как язык, но продукты какие-то тормознутые и жрущие память(память ест, занимает, сама среда видать, для выполнения программы). А вопрос собственно почему так? И излечимо ли это? Или тот кто программит на Java, программит только сервачные приложения?
ага, а модельные тесты и диаграммы «неотставания» джавы обычно делаются на каких-то совсем простых примерах, где в действительности можно просто «научить» VM справляться с ними по-особому. когда сам экспериментировал с джава-кодом получал более чем десятикратное отставание, но задача была связана с очень активным использованием памяти, а на джаве я вряд ли пишу хорошо, но вот так.
Рендеринг интереса в яве может задействовать возможности графического ускорителя, тогда по скорости прорисовки он станет быстрее нативных компонент. Но это нужно включать руками и при условии что у вас современная видекарта.

В 7ке обещали, что ускорение будет включать по умолчанию. Но в общем вы правы. Графические библиотеки Swing невероятно прожорливые и тяжёлые. Но в яве возможно использование сторонних нативных графических библиотек, таких как SWT/XWT, Qt Jambi, или, если вы совсем круты, то через AWT можете получить доступ виджетам операционной системы. Все это даст существенный рост производительности интерфейса. Но за это придется заплатить потерей переносимости между платформами.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
SunJDK или OpenJDK?
Оракл заявила, что с седьмой версии SunJDK или OpenJDK будут соединенны в один единый проект, который будет распространяться под названием OpenJDK и лицензией GPL. Еще забыл добавить, что сейчас довольно мучительно, но стабильно развивается технология JavaFX, которая должны позволить создавать эффективные и быстрые пользовательские интерфейсы… но что получится на самом деле посмотрим. Пока развитие JavaFX обнадеживает.
Старно, может быть направление и обнадеживает, но темпы развития, и распространенность… А с учетом того, что действительно все все больше смотрят в строну html5, то как то смутно видятся перспективы javaFX
Не знаю. Я так подозреваю, что JavaFX это попытка реинкарнировать ява аплеты с учетом прошлых ошибок. В отличие от флеш, хтмл5 и прочего, аплеты представляют возможности реального межплатформного десктопного приложения в браузере. И хотя такие решения не новы, почти все альтернативы либо привязаны к браузеру, либо к оси. Как ни крути, но получить в браузере полноценное десктопное приложение на хтмл5 либо очень сложно.

Лично я до считаю, что технология ява аплетов была сильно недооценена. Люди так и не поняли, что с ней можно делать. Возможно она просто слишком рано появилась на рынке и поначалу сильно страдала детскими болезнями технологии. Да и железо тогда было намного слабее и ява тогда реально тормозила. Сегодня ява избавилась от многих проблем, отвративших людей от аплетов, но стереотипы сильна вещь. Нужен принципиальный редизайн технологии, чтобы люди снова ею заинтересовались. А там посмотрим. Мне лично такая технология интересна. Я уже планирую на осень крупный проект на JavaFX.
> Чаще всего HotSpot выдвигает гипотезы о структуре алгоритма по стандартным патернам проектирования.
> Именно поэтому всех Java программистов учат как можно чаще использовать патерны проектирования.

Откуда Вы это взяли?
Из документации.
Java Virtual Machine Specification? Java Language Specification?
Не покажете место?
Очевидно же, что в спецификации языка этого быть не может.

Этот материал был подробно разжеван в докладе Sun Tech Days в России 2010 — Современная виртуальная машина Java изнутри. К сожалению видеозапись на сервере более недоступна. Если удастся обратиться к разработчикам то может они восстановят запись, так как доклад получился шикарным.

А так же доклады на конференции JavaOne Oracle Develop Россия 2011- Искусное тестирование производительности, и Производительность Java-платформы.
Очевидно, что в JVMS этого также нет.

Ознакомился детально со всеми презентациями по ссылкам, ни слова про распознавание JIT-ом паттернов проектирования я, само собой, не нашел. Допускаю, что на докладах произносилось что-нибудь вроде «code patterns», если оно было на английском, откуда могла пойти путаница.

В общем, в статье есть интересные вещи, но читать ее не специалисту опасно — некоторые неточности могут завести совсем не туда.
Ну тогда вам придется читать всю спецификацию, что бы понять почему во всех обучающих книгах книгах по ява рекомендуют использовать патерны. Потому что я вам не смогу привести точную ссылку на этот материал, я его просто помню, а вот указать вам точное место, где я это прочел к сожалению не смогу… да не помню я просо. На англоязычных форумах по ява эта информация часто проскакивает. Но опять так я это говорю без ссылок.

Доклады были на русском языке и там подробно рассказывалось как JVM выдвигает гипотезы и за тем расставляя счетчики пытается доказать или опровергнуть свои гипотезы. По этой теме есть неплохой доклад Java HighLoad… Но опять про патерны там нет ничего… Я так понял что вас интересует связь между патернами и оптимизациями? Постараюсь найти подтверждение, но боюсь понять эту тему можно только изучая код OpenJDK возможно что этого даже нет и в спецификации. Потому что это особенность конкретной имплиментации JVM HotSpot. Другие JVM могут работать совершенно иначе и делать это хуже или лучше.
Гугл, только что подсказал, что один из авторов докладов по производительности это пользователь TheShade :) Если он согласится, то возможно он даст вам видео с конференций. Там есть что посмотреть и послушать.
«Даже если вы сможете придумать оригинальный эффективный алгоритм, то это не значит, что ваша программа будет работать быстрее, скорее наоборот. HotSpot будет слишком часто выдвигать ошибочные гипотезы о вашем коде, проводить деоптимизации и рекомпиляции до тех пор пока не сможет найти оптимальный способ компиляции вашего алгоритма. И не факт что JIT оптимизация нестандартного алгоритма, будет лучше, чем оптимизация громоздкого патерна. Инженеры SUN в свое время провели огромную работу, чтобы научить Java эффективно работать с патернами.»
У вас есть авторитетный источник для вот этого вот утверждения? :) И как связаны паттерны с алгоритмами?
Это было на Sun Tech Days в России 2010 к сожалению видеоматериал этого доклада более не доступен. Так же это можно узнать в Java Virtual Machine Specification… хотя там про адаптивную оптимизацию сказано мало потому что каждая реализация JVM может это делать по своему и это не является стандартом. Если мне не верите, то спросите в личке TheShade, он работает в Оракле над префомансом JVM. Я думаю что для вас он будет поавторитетнее меня. Если я ошибаюсь, то буду благодарен вам если вы сможете меня поправить. Тогда я поправлю статью. Но пока у меня нет материала указывающего на это.
За Фромма — отдельное большое спасибо!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации