php против node js
UA Blog
Blog on instersting topics
Не смотря на то что PHP и Node.js могут справляться с приложениями любой сложности, они созданы на основе разных концепций и архитектур. Если вы владелец приложения выбирающий между двумя платформами, вы должны иметь в виду их основные преимущества и недостатки. Node.js и PHP одни из самых часто используемых средств для разработки веб-сайтов. PHP — скриптовый язык созданный Rasmus Lerdorf в 1994, являлся языком номер один ери Web 1.0. Показательное проявление успеха PHP являются системы управления контентом, такие как WordPress, Joomla и Drupal, с их помощью работают миллионы блогов и веб порталов. Node.js это представитель более новых технологий веб-разработки. В отличии от PHP, Node.js не является языком программирования, это среда выполнения которая использует JavaScript для написание приложений на стороне сервера. Представлен в 2009, Node.js продемонстрировал силу JavaScript при разработке событийно-ориентированных, data-driven приложений эпохи Web 2.0
Плюсы Node.js
1) Быстрое серверное решение
Node.js позволяет используя очередь событий JavaScript создавать приложения с неблокирующим вводом/выводом которые способны обрабатывать несколько запросов одновременно. Используя встроенною в JavaScript асинронность, можно создавать высокомасштабируемые серверные приложения, которые максимизируют использование одного CPU и памяти компьютера при одновременной обработке большего количества запросов, чем обычные многопоточные серверы. Такая функциональность делает Node.js прекрасным выбором для приложений реального времени и те которые требуют большого количества операций ввода/вывода
2) Один язык на фронт-енде и бекенде
Много популярных JS фреймворков таких как React или Vue написаны на JavaScript, который является основным языком всех современных браузеров. Используя Node.js на сервере вы получаете все преимущества скриптового языка на обеих платформах. Иметь один язык на фронт-енде и бекенде очень хорошо для обеспечения поддержки вашего приложения і координации меєду членами вашей команды.
Node.js не имеет строгих правил или жестких зависимостей, что оставляет простор для созидания и креативности при разработке приложений. Разработчики сами выбирают архитектуру, зависимости.
Недостатки Node.js
1) Малая эффективность в операциях интенсивно использующих CPU
Событийно-ориентированная архитектура Node.js имеет некоторые ограничения а именно низкую эффективность при большой нагрузки на CPU. Хотя и Node хорошо справляется конкурентной обработкой множества запросов, он все же плохо справляется с таким операциями как генеррование графики, обработка изображений. К счастью, существует обходной путь в котором можно выполнять такие операции по очереди или в отдельном процессе.
2) Незрелость платформы
Вместе с стабильными стандартными библиотеками такие как HTTP or Crypto, доступно множество библиотек от сторонних разработчиков. Эта екососитема еще не достаточно сфомировалась, и к сожаление приходится зависеть от не очень качесвенно протестированых модулейю
Плюсы PHP
1) Большая кодовая база
PHP огормною кодовою базу для всевозможных решений от систем управления контентом до мощных фреймворков таких как Laravel, Symfony. Например с помощью WordPress можно запустить свой блог за считанные минуты.
2) Переносимое решения
PHP достаточно независим от платформы, он может быть запущен почти на любом сервере и на любой платформе.
В тоже время, имеется широкий выбор хостингом которые с поддержкой PHP, и вам не нужно арендовать полноценный сервер с SSH доступом чтобы запустить ваш проект, в отличии от Node.js. Из этого следует что интеграция PHP проектов и их развертывание несколько проще для небольших компаний или для отдельных лиц который могут запускать и управляиь своими приложениями без знаний консольных команд, системы Linux
3) Спроектирована для WEB В отличии от Java или Python и других языков программирования общего назначения, PHP был разработан специально для Web. Именно поэтому он содержит всю необходимую функциональность для работы с HTML, серверами, базами данных. C всеобъемлющим языком PHP, в большинстве случаев можно обойтись минимальным количеством JS кода на фронт-енде.
Недостатки PHP
1) Плохое разделение ответственности (SoC)
PHP не очень хорош в реализации паттерна MVC, который является рекомендованным в веб-разработке. Очень часто можно можно встретить микс HTML и PHP, что выливается в не очень красивый и сложно поддерживаемый код, где бизнес логик смешана с представлением
2) Устаревшая клиент-серверная модель
Сравнение Node.js и PHP
Языки программирования PHP и JavaScript раньше были союзниками и каждый из них занимал свою сферу и оба были обязательными для нормальной работы сайтов. Сферы назначения языков были явно разделены, JavaScript работал на стороне пользователя в браузере, в то время как PHP выполнял все серверные задачи. По такому принципу сейчас работает множество сайтов и систем управления, таких как WordPress, Drupal и Facebook. Вы вряд ли можете пользоваться интернетом больше пяти минут без PHP.
Обе платформы продолжают расширяться, улучшатся и получать больше возможностей. Теперь существует множество фреймворков для Node.js, например, Express, Angular, Meteor, и другие. В свою очередь, PHP тоже продолжает развиваться. Компилятор Zippy обеспечивает более быструю работу, чем когда-либо, благодаря там же методам, что сделали революцию Node.js. PHP 7 и HHVM уже имеют большинство из тех оптимизаций, которые использовались в V8 для Chrome и Node.js. Кроме того, HHVM поддерживает язык Hack, который имеет поддержку сложных функций, таких как лямбда, генераторы и коллекции.
Конечно, результат этого противостояния еще неизвестен. Для одних программистов очень важна чистота Node.js и простота использования JavaScript. Другие уже привыкли к стабильности и отличной кодовой базой PHP. Сможет ли Node.js победить? Или PHP удержит свои позиции.
Смешивание кода с содержимым
Допустим, вы верстаете страницу для своего сайта, вы хотите разместить текст, а в нем различные данные из базы данных, памяти или других мест. Все это делается очень просто с помощью вставки тегов PHP. Вы можете использовать шаблонизатор, но это вовсе не обязательно. Здесь не нужно дополнительных файлов или сложных архитектур приложения.
Количество готовых решений
Существует очень много кода и платформ, написанных на PHP. Это такие популярные платформы, как WordPress, Drupal, Joomla. Кроме того, они имеют открытый исходный код, как и большинство плагинов для них. Вы можете их свободно загружать модифицировать и использовать по своему усмотрению.
Но несмотря на это, многие из тех же плагинов для WordPress давно не обновлялись и уже давно потеряли совместимость со свежими версиями платформы. С другой стороны, все плагины и фреймворки для Node.js еще новые. Они разработаны с учетом новейших технологий. Их меньше, но общая совместимость больше. Конечно, такая судьба может в будущем постичь и Node.js, когда будут придуманы более совершенные способы работы. Если выбирать Node.js или PHP под этим углом обзора, то я выбрал бы PHP, потому что кода и библиотек для работы с различными сервисами в разы больше.
Простота использования
По своей сути PHP очень прост. Здесь есть несколько переменных и основные функции для управления текстом, числами и файлами. Функции реализуют почти все, необходимые функции. Но, фактически, это слой, предназначенный для передачи данных, полученных от порта 80 в базу данных и обратно. Это основная задача. Часто сложные задачи по сортировке и выборке данных перекладываются на базу данных.
При выборе Node js или PHP JavaScript может показаться очень сложным, на первый взгляд. Он имеет несколько примечательных особенностей, которые могут показаться непонятными, но в основном, это современный язык с такими новыми возможностями, как, например, замыкания. Вы можете использовать такие библиотеки, как JQuery. Вы можете использовать возможности всех подобных объектов. И это очень полезно.
Новые возможности
Если вам нужно получить больше чем просто взаимодействие с базой данных и форматирование результатов, вы можете подключить HHVM и получить поддержку Hack, современного языка от Facebook, с поддержкой аннотации типа, лямбда-функциями и генераторами. Но тогда ваш код будет работать только с HHVM, хотя это не так плохо, потому что он будет работать в разы быстрее.
Но если вам нужны функции из Hack, то стоит задуматься о переходе на Node.js. Многие современные языки могут быть скомпилированы в Node.js и JavaScript. Среди них: Java, C#, Lisp и десятки других, таких как Scala, OCaml, Haskell. Также есть поддержка компиляции Basic и Pascal для любителей этих языков.
Способ передачи данных
Использование одного языка на сервере и в браузере это очень хорошо, но что, если вам нужно отправлять данные в чистом HTML? Браузер отлично обрабатывает HTML, нет никаких проблем с ошибками при попытке создать страницу в JavaScript с помощью вызова нескольких десятков служб. Чистый HTML работает лучше и PHP лучше ориентирован на это. Вы можете генерировать страницы на сервере и не заботится про поддержку в браузере.
Хранение данных
PHP оптимизирован и отлично работает с базой данных MySQL, здесь поддерживаются различные версии баз данных, как MariaDB, Postgresql, MySQL. Ваш код может работать со всеми базами независимо от используемых движков.
Если вам очень нужен доступ к SQL, то у Node.js есть библиотеки и для этого, но здесь также есть поддержка специального формата работы с данными. Это JSON. С помощью него вы можете взаимодействовать с новыми типами баз данных NoSQL. Это не значит, что вы не можете настроить поддержку JSON для вашего PHP проекта, но наиболее удобно его использовать вместе с JavaScript. Вы получаете один и тот же код для браузера и сервера.
Скорость работы и разработки
Для большинства программистов написание PHP кода очень просто и быстро. Здесь не нужно различных компиляторов или преобразователей. Вы просто пишете свой код в блокноте и уже можете выполнять. Если нужно сделать проект очень быстро, то PHP будет отличным инструментом.
Написание кода на JavaScript немного сложнее, вам придется рассчитывать фигурные скобки, и т д. Но когда вы все сделаете, ваш код будет летать. Механизм обратного вызова это еще одна интересная вещь, поскольку она избавляет вас от ожидания.
Развитие
PHP постоянно развивается. Кроме развития самого языка, команда которого недавно выпустила седьмую версию, развиваются проекты HHVM и Zend, которые дают максимальную скорость выполнения, новые возможности и ту же концепцию MVC. Принцип MVC применяется во многих новых проектах.
Node.js тоже активно развивается, но здесь есть одно отличие PHP vs Node.js. Node содержит все современные функции в одном основном дистрибутиве. Здесь нет такой фрагментации. Это большой плюс, потому что разработчикам не придется тратить время на переработку кода.
Выводы
В этой статье мы сделали сравнение Node js и PHP. Это отличные платформы для разработки сайтов и веб-приложений. На каждом из них можно создать отличный сайт, но у обоих есть свои плюсы и минусы. Хотя мы не приводили технических подробностей, надеюсь, вы смогли для себя определить, что вам больше подходит.
php и nodejs, разница на пальцах
Являясь постоянным пользователем форума nodejs.ru, часто наблюдаю картину когда люди начиная изучать nodejs сравнивают ее с php, а иногда пытаются работать с ней так как с php. Я бы хотел объяснить “на пальцах” разницу между php и nodejs применительно к работе сайта. Статья предназначена для новичков. Я намеренно буду говорить очень упрощенно, не вдаваясь в глубокие подробности, что бы как можно проще показать различия в технологиях.
Что то объяснять всегда лучше на наглядном примере с картинками. Поэтому придумаем небольшой “сферический сайт в вакууме” и примем некоторые условия.
Пусть у нас имеется некий сайт, который понимает всего два запроса:
Запрос А выполняется за 1 секунду, он не требует обращение к БД.
Запрос Б выполняется за 5 секунд, причем 4 из них, он тратит на ожидание ответа БД.
Так же условимся что время между запросами не менее 1 секунды.
Давайте рассмотрим как это работает на php.
В самой упрощенной форме архитектура сервера выглядит так:
Важно тут следующие, веб сервер получив запрос от клиента передает его в php процесс. В свою очередь процесс php в один момент времени может обрабатывать один запрос, по завершению работы, результат возвращается веб серверу, а сам процесс перестает существовать. Веб сервер получая ответ отправляет результат клиенту и закрывает соединение.
При наличии всего одного php процесса, работа нашего сервера можно отобразить на такой схеме:
Из схемы видно, что пока к нам поступают только запросы А наш сервер бодро на них отвечает и в целом выполняет поставленным задачи, но как только к нам приходит запрос Б, сервер перестает отвечать на запросы, до момента пока не будет готов ответ на запрос Б. Так же на схеме видно что большую часть времени запроса Б “все” ждут результат работы базы данных.
Для решения этой проблемы приходиться увеличивать кол-во php процессов, давайте увеличим до 2х, в результате схема принимает такой вид:
Из этой схемы видно, что запрос Б “повисает” в обработке в первом php процессе, при этом сервер продолжает отвечать на остальные запросы. Все будет идти хорошо до момента, когда к нам не придут два запроса Б, тогда оба php процесса “повиснут” в ожидании ответа базы, и сервер в целом перестанет отвечать, до момента пока один из них не освободиться.
Ну мы то уже знаем что делать? Правильно, возьмем и увеличим кол-во php процессов, сразу до 20 или 30 и проблема вроде как ушла, хотя на самом деле проблема просто немного отдалилась и момент когда придет 30 запросов Б наступит. Вся беда в том что мы не можем создавать бесконечно много php процессов и путь наращивать их в запредельных количествах неверен.
Самое главное в что следует вынести из этих схем, это то, что операции работы с базой данных в php выполняются синхронно. В нашем случае процесс выполнивший запрос к базе неспособен обработать другие запросы и вынужден “висеть” (ничего не делая) ожидая ответ от базы данных.
nodejs
Что дает нам nodejs?
Сначала посмотрим как выглядит простой сервер:
Сразу бросается в глаза то, что сервер включает в себя обработчики непосредственно запросов А и Б, а так же сам Веб сервер. Всё это добро крутится в одном node процессе и постоянно висит в памяти.
Посмотрим на схему работы:
На схеме хорошо видно что запросы Б не приводят к “подвисанию” сервера в ожидании ответа базы. Сервер получив запрос Б, просто сформирует и отправит запрос в базу данных, и продолжит отвечать на остальные запросы, как только ответ от базы будет получен, сервер вернет результат клиенту. В случае nodejs неважно как и в каком количестве придут запросы Б, ни один из них не приведет к “подвисанию” в ожидании ответа базы.
Различия асинхронной и многопоточной архитектуры на примере Node.js и PHP
Многопоточная модель
Эта модель известна каждому. Наше приложение создает некоторое количество потоков (пул), передавая каждому из них задачу и данные для обработки. Задачи выполняются параллельно. Если потоки не имеют общих данных, то у нас не будет накладных расходов на синхронизацию, что делает работу достаточно быстрой. После завершения работы поток не убивается, а лежит в пуле, ожидая следующей задачи. Это убирает накладные расходы на создание и удаление потоков. Именно по такой системе и работает вебсервер с PHP. Каждый скрипт работает в своем потоке. Один поток обрабатывает один запрос. Потоков у нас достаточно большое количество, медленные запросы забирают поток надолго, быстрые — обрабатываются почти мгновенно, освобождая поток для другой работы. Это не позволяет медленным запросам забирать все процессорное время, заставляя подвисать быстрые запросы. Но у такой системы есть определенные ограничения. Может возникнуть ситуация, когда к нам придет большое количество медленных запросов, например работающих с БД или файловой системой. Такие запросы заберут себе все потоки, что сделает невозможным выполнение других запросов. Даже если запросу нужно всего 1мс на выполнение — он не будет вовремя обработан. Это можно решить увеличением числа потоков, чтобы они могли обработать достаточно большое количество медленных запросов. Но к сожалению потоки обрабатываются ОС, ей же выделяется и процессорное время. Поэтому чем больше потоков мы создаем, тем больше накладных расходов на их обработку и тем меньше процессорного времени выделяется каждому потоку. Ситуация усугубляется самим PHP — блокирующие операции работы с БД, файловой системой, вводом-выводом так же тратят процессорное время, не выполняя в этот момент никакой полезной работы. Тут мы поподробнее остановимся на особенностях блокирующих операций. Представим себе такую ситуацию: у нас имеется несколько потоков. Каждый обрабатывает запросы, состоящие из 1мс обработки самого запроса, 2мс на доступ и получение данных из БД и 1мс рендеринга полученных данных. Всего на каждый запрос мы тратим, таким образом, 4мс. При отправке запросов к БД поток начинает ожидать ответа. Пока данные не вернутся — поток никакой работы выполнять не будет. Это 2мс простоя на запрос в 4мс! Да, мы не можем сделать рендеринг страницы, не получив данные из базы. Мы обязаны ждать. Но ведь при этом мы получаем 50% простоя процессора! А сюда сверху можно накинуть дополнительные расходы ОС на выделение процессорного времени каждому потоку. И чем потоков больше — тем больше этих расходов. В итоге мы получаем довольно большое время простоя. Это время напрямую зависит от длительности запросов к БД и файловой системе. Лучшее решение, которое позволяет нам полностью загрузить процессор полезной работой это переход к архитектуре, использующей неблокирующие операции.
Асинхронная модель
Менее распространенная модель, нежели многопоточная, но имеющая не меньшие возможности. Асинхронная модель построена на очереди событий (event-loop). При возникновении некоторого события (пришел запрос, выполнилось считывание файла, пришел ответ от БД) оно помещается в конец очереди. Поток, который обрабатывает эту очередь, берет событие с начала очереди, и выполняет связанный с этим событием код. Пока очередь не пуста процессор будет занят работой. По такой схеме работает Node.js. У нас имеется единственный поток, обрабатывающий очередь событий (с модулем cluster — поток будет уже не один). Почти все операции неблокирующие. Блокирующие тоже имеются, но их использование крайне не рекомендуется. Далее вы поймете почему. Возьмем тот же пример с запросом 1+2+1мс: из очереди сообщений берется событие, связанное с приходом запроса. Мы обрабатываем запрос, тратим 1мс. Далее делается асинхронный неблокирующий запрос к базе данных и управление сразу же передается дальше. Мы можем взять из очереди следующее событие и выполнить его. К примеру мы возьмем еще 1 запрос, проведем обработку, пошлем запрос к БД, вернем управление и проделаем то же самое еще один раз. И тут приходит ответ БД на самый первый запрос. Событие, связанное с ним помещается в очередь. Если в очереди ничего не было — он сразу же выполнится, данные отрендерятся и отдадутся назад клиенту. Если в очереди что-то есть — придется подождать обработку других событий. Обычно скорость обработки одного запроса будет сравнима со скоростью обработки многопоточной системой и блокирующими операциями. В худшем случае — на ожидание обработки других событий потратится время, и запрос обработается медленнее. Но зато в тот момент, пока система с блокирующими операциями просто ждала бы 2мс ответа, система с неблокирующими операциями успела выполнить еще 2 части 2х других запросов! Каждый запрос может выполняться чуточку медленнее в целом, но в единицу времени мы можем обработать гораздо больше запросов. Общая производительность будет выше. Процессор всегда будет занят полезной работой. При этом на обработку очереди и переходе от события к событию тратится гораздо меньше времени, чем на переключение между потоками в многопоточной системе. Поэтому асинхронные системы с неблокирующими операциями должны иметь не больше потоков, чем количество ядер в системе. Node.js изначально вообще работал только в однопоточном режиме, и для полного использования процессора приходилось вручную поднимать несколько копий сервера и распределять нагрузку между ними, например, с помощью nginx. Сейчас для работы с несколькими ядрами появился модуль cluster (на момент написания статьи все еще имеющий статус experimental). Вот тут и проясняется ключевое отличие двух систем. Многопоточная система с блокирующими операциями имеет большое время простоя. Чрезмерное количество потоков может создать много накладных расходов, недостаточное же количество может привести к замедлению работы при большом количестве медленных запросов. Асинхронное приложение с неблокирующими операциями использует процессорное время эффективнее, но более сложно при проектировании. Особенно сильно это сказывается на утечках памяти — процесс Node.js может работать очень большое количество времени, и если программист не позаботится об очистке данных после обработки каждого запроса, мы получим утечку, что постепенно приведет к необходимости перезагрузки сервера. Также существует асинхронная архитектура с блокирующими операциями, но она гораздо менее выгодна, что можно будет увидеть далее на некоторых примерах. Выделим особенности, которые необходимо учитывать при разработке асинхронных приложений и разберем некоторые ошибки, возникающие у людей при попытке разобраться с особенностями асинхронной архитектуры.
Не используйте блокирующие операции. Никогда
Ну по крайней мере пока не поймете полностью архитектуру Node.js и не сможете аккуратно работать с блокирующими операциями.
При переходе с PHP на Node.js у некоторых людей может возникнуть желание писать код в таком же стиле, как и раньше. Действительно, если нам надо сперва считать файл, и только потом приступить к его обработке, то почему мы не можем написать следующий код:
Этот код правильный и вполне рабочий, но он использует блокирующую операцию. Это значит что до тех пор, пока файл не будет прочитан, очередь сообщений обрабатываться не будет и Node.js будет просто висеть, не совершая никакой работы. Это полностью убивает основную идею. В то время, пока файл читается, мы могли бы выполнять другую работу. Для этого мы используем следующую конструкцию:
Разберем ее подробнее: у нас происходит асинхронное чтение из файла, при вызове функции чтения управление сразу же передается дальше, Node.js обрабатывает другие запросы. Как только файл будет считан — вызывается анонимная функция, переданная в readFile вторым параметром. А точнее событие, связанное с ней, ложится в очередь и когда очередь доходит до нее — выполняется. Таким образом, мы не нарушаем последовательность действий: сперва считывается файл, потом обрабатывается. Но при этом мы не занимаем процессорное время ожиданием, а позволяем обрабатывать другие события в очереди. Это обстоятельство очень важно помнить, так как всего несколько неаккуратно вставленных синхронных операций могут сильно просадить производительность.
Используйте такой код, и вы безнадежно убьете event-loop:
Такой кусок кода будет занимать все процессорное время себе, не давая обработаться другим событиям. Пока проверка не завершится успешно, цикл будет повторяться, и никакой другой код не выполнится. Если вам необходимо дождаться какого-либо события то… используйте события!
Опять-таки, этот код выполнится только после выполнения определенного условия. Только эта проверка не запускается в цикле — код, выполняющий наше условие, с помощью функции emit вызывает событие, на которое мы вешаем обработчик. Объект events.EventEmitter отвечает за создание и обработку наших событий. eventEmitter.on отвечает за выполнение кода, при возникновении определенного события.
На этих примерах можно увидеть, как неосторожное использование блокирующего кода останавливает обработку очереди событий и соответственно стопорит работу всего Node.js. Для предотвращения таких ситуаций используйте асинхронный код, завязанный на событиях. Используйте асинхронные операции вместо синхронных, используйте асинхронные проверки наступления некоторого события.
Не используйте больших циклов для обработки данных. Используйте события
Что произойдет, если у нас возникает необходимость использовать громадный цикл работы с данными? Что если у нас должен быть цикл, работающий в течении жизни всей программы? Как мы уже выяснили выше — большие циклы приводят к блокировке очереди. Когда потребность в цикле все же возникает, мы заменяем его на создание событий. Каждая итерация цикла создает событие для последующей итерации, положив его в очередь. Таким образом, мы пропустим все события, которые ждали в очереди своего часа и после их обработки приступим к новой итерации, не блокируя очередь.
Данный код выполнит тело цикла и создаст событие для следующей итерации. Никакой блокировки очереди событий в таком случае не будет.
Не создавайте больших операций, занимающих много процессорного времени
Иногда возникает потребность в обработке громадного объема данных или выполнение ресурсоемкого алгоритма (хотя писать злой матан на Node.js — не лучшая идея). Такая функция может занимать много процессорного времени (скажем, 500мс) и пока она не выполнится, много маленьких запросов будут простаивать в очереди. Что делать если такая функция все-таки есть и отказаться от нее мы никак не можем? В таком случае выходом может стать разбиение функции на несколько частей, которые будут вызываться поочередно как события. Эти события будут ложиться в конец очереди, тогда как события сначала могут пройти, не дожидаясь, пока наш увесистый алгоритм выполнится полностью. В вашем коде не должно быть больших последовательных кусков, не разбитых на отдельные события. Конечно есть еще выход в виде создания своего модуля на си, но это уже из другой оперы, не относящейся к вопросам асинхронного проектирования.
Внимательно следите за тем, какой тип функции вы используете
Читайте документацию, для того чтобы понять используете ли вы синхронную или асинхронную, блокирующую или неблокирующую функцию. В Node.js принято именовать синхронные функции с постфиксом Sync. В асинхронных функциях обработчик события по завершению функции обычно передается последним параметром и именуется callback. Если же вы используете асинхронную функцию там, где хотели использовать синхронную, у вас могут возникнуть ошибки.
Разберем данный код. Начинается неблокирующее считывание файла асинхронным способом. Управление сразу же передается дальше — записывается ответ пользователю. Но при этом файл еще не успел считаться. Соответственно мы отдадим пустой ответ. Не забывайте, что при работе с асинхронными функциями, код для обработки результата функции всегда должен располагаться внутри callback-функции. Иначе результат работы непредсказуем.