Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Вопрос к программистам [9]

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (9): « 1 2 3 4 5 6 7 8 [9]   

> Описание: Комбинаторика, алгоритмы и прочее - в программном коде
ALEN Модератор
Отправлено: 26 Сентября, 2013 - 10:06:39
Post Id



Участник


Покинул форум
Сообщений всего: 1459
Дата рег-ции: Авг. 2008  
Откуда: Крым


Помог: 11 раз(а)




LIME, тогда поправлюсь: "Очередь выполнения".
 
 Top
LIME
Отправлено: 26 Сентября, 2013 - 10:08:33
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




ALEN а в чем состоит поправка?
 
 Top
EuGen Администратор
Отправлено: 26 Сентября, 2013 - 10:10:20
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Итак, чтобы более не затягивать ответ - опишу ситуацию как можно подробнее - насколько смогу. Прежде всего, прошу прощения за некий вызов, сделанный мною сообществу в hint1 - это было сделано не с целью выразить мысль "всё равно не ответите", а с целью подогреть интерес. Надеюсь, ни один пользователь не в обиде.

Итоги и направление мыслей

На самом деле, полный ответ на поставленный вопрос уходит далеко за рамки обычного использования PHP. Скажу, что наиболее правильные мысли были выражены Ильёй (DeepVarvar) и caballero (к сожалению, не знаю имени). Илья предположил, что дело в том, как интерпретатор работает с такими выражениями на уровне байткода (п. 2 в комментарии), тогда как caballero разумно предложил посмотреть, что происходит на ассемблерном уровне. На самом деле, ассемблерный уровень показал бы, что это действительно так происходит, но не показал бы, почему это так - поскольку это уже скомпилированные из опкодов готовые процессорные инструкции. Правда кроется как раз в опкодах, которые получаются после интерпретации программы и которые затем исполняются в Zend VM.

Ассоциативность и приоритет

Многие предполагали, что суть дела состоит в приоритете операторов или в некоторой ассоциативности. Отчасти это правда, однако без понимания, как именно это работает, ответ всё равно не очевиден. Правда состоит в том, что на самом деле выражения в PHP не выполняются с учётом ассоциативности и приоритета. Ассоциативность и приоритет лишь показывают, как выражения будут сгруппированы - но не порядок их дальнейшего исполнения. Почувствуйте разницу. Для обсуждаемых примеров:
CODE (php):
скопировать код в буфер обмена
  1. //в первом выражении:
  2. $x + $x++;
  3. // "++" имеет более высокий приоритет, чем "+", поэтому "$x++" будет сгруппирован, что равносильно
  4. $x + ($x++);
  5.  
  6. //во втором выражении:
  7. $x + $x + $x++;
  8. // и снова "++" имеет более высокий приоритет, чем "+", так что группировка будет такой:
  9. $x + $x + ($x++);
  10. // и, наконец, "+" - это лево-ассоциативный оператор, поэтому левый "+" будет сгруппирован (но не правый!):
  11. ($x + $x) + ($x++);

Понятнее? Наверно. Однако - что это значит в плане порядка вычисления выражения? А ничего. В последнем выражении левая часть ($x + $x) или же правая ($x++) - могут вычисляться первыми. И PHP не регламентирует, что же случится в таком случае на самом деле. Поэтому вывод таков - не стоит полагаться на это (то есть ошибочно считать, что ассоциативность и приоритет определяют порядок выполнения выражения) в своих программах. Однако же это не даёт полного ответа, верно? И тем более про случай с "@".

Оптимизация "компилированных переменных"

Если предыдущая часть ещё могла быть предположена (хотя ни из одного руководства это явно не следует), то эта - уже намного более специфична - и именно здесь скрыт ответ, почему так происходит в обсуждаемых примерах.
Немного пояснений. PHP исполняется в два этапа. На первом этапе интерпретатор проходит программу и генерирует опкоды - некоторые инструкции, которые имеют два операнда и инструкцию, к которой эти операнды применяются. Затем опкоды исполняются в Zend VM (Zend Virtual Machine) для получения уже готовых машинных инструкций.
Начиная с версии 5.1 в PHP введена функциональность оптимизации "компилированных переменных" (compiled variables optimization). Эта оптимизация позволяет простым переменным быть непосредственно операндами самих опкодов. Простые переменные - это, например, $foo или $bar - но не $foo->bar или $foo['bar']. Итак, можно проверить, что же получится в результате обработки первого примера в терминах опкодов:
CODE (text):
скопировать код в буфер обмена
  1. //код второго примера:
  2. $x = 1;
  3. $y = ($x + $x) + ($x++);
  4.  
  5. //опкоды:
  6.          ASSIGN   $x, 1
  7. $tmp_1 = ADD      $x, $x
  8. $tmp_2 = POST_INC $x
  9. $tmp_3 = ADD      $tmp_1, $tmp_2
  10.          ASSIGN   $y, $tmp_3

- в принципе, должно быть интуитивно понятно соответствие опкодов операциям программы. Обратите внимание, что $x может участвовать в опкодах непосредственно - так как она является простой переменной. На всякий случай, всё же поясню: сначала присвоить $x значение 1 (ASSIGN $x, 1), затем добавить к $x её же и сохранить результат в $tmp_1 ($tmp_1 = ADD $x, $x), затем выполнить постинкремент для $x и сохранить результат в $tmp_2 ($tmp_2 = POST_INC $x), затем сложить $tmp1 и $tmp2 с сохранением результата в $tmp_3 ($tmp_3 = ADD $tmp_1, $tmp_2) - и, наконец, присвоить $x конечное значение выражения (ASSIGN $y, $tmp_3). Как видно, в данном примере вычисление произошло слева направо (вероятно, ожидаемый порядок)
Теперь первый пример.
Опкоды, которые получатся в результате, будут такими:
CODE (text):
скопировать код в буфер обмена
  1. //код первого примера:
  2. $x = 1;
  3. $y = $x + ($x++);
  4.  
  5. //опкоды
  6.          ASSIGN   $x, 1
  7. $tmp_1 = POST_INC $x
  8. $tmp_2 = ADD      $x, $tmp_1
  9.          ASSIGN   $y, $tmp_2

- как видно, в данном случае постинкремент выполнился сначала, значение же $x было прочитано только после опкода ADD. Почему так? Потому что чтение значения $x не требует дополнительного опкода. Любой опкод может обработать операцию "прочтения" значения переменной в силу "оптимизации компилированных переменных". В этом и есть её суть - то есть, так как переменная указывает на своё же значение, то такого опкода для чтения и не требуется (в этом и состоит оптимизация). Таким образом, опкод одновременно начинает читать значение и, собственно, выполняться.

Как этого избежать?

Существуют некоторые весьма редкие случаи, когда оптимизация компилированных переменных не выполняется. К таким случаям относится использование оператора "@". Разберу пример с его использованием:
CODE (text):
скопировать код в буфер обмена
  1. //код примера:
  2.   $x = 1;
  3. @ $y = $x + $x++;
  4.  
  5. //опкоды:
  6.          ASSIGN        $x, 1
  7. $tmp_1 = BEGIN_SILENCE
  8. $var_3 = FETCH_R       'x'
  9. $tmp_4 = POST_INC      $x
  10. $tmp_5 = ADD           $var_3, $tmp_4
  11. $var_2 = FETCH_W       'y'
  12.          ASSIGN        $var_2, $tmp_5
  13.          END_SILENCE   $tmp_1

- как видно, применение этого оператора существенно поменяло картину. Теперь всё заключено внутри опкодов BEGIN_SILENCE/END_SILENCE - однако это не главное. Главное - в том, что теперь, вместо описанной выше оптимизации, PHP применил опкоды FETCH_R (получение для чтения) и FETCH_W (получение для записи) к $x и $y - вместо того, чтобы эти самые $x и $y использовать в качестве операндов для опкодов. И в этом и состоит вся суть - теперь значение будет получено до применения опкода сложения, тогда как в случае оптимизации этого не происходило. А сделано до сложения это будет, разумеется потому, что $var_3 = FETCH_R 'x' теперь самый настоящий, "полноценный" опкод и порядок для него уже имеет значение.

Резюме

Откуда это всё взялось? Примеры появились, конечно, искусственно, но в ходе достаточно оживлённой дискуссии, в которой мне посчастливилось поучаствовать. Это - не то, что можно прочесть из руководств. Строго говоря, это вообще нигде нельзя прочесть, потому что многое было получено непосредственно из чтения исходных кодов интерпретатора и опкодов для VM. В нормальной ситуации такой проблемы не возникнет, так как опытный разработчик, в случае неуверенности, просто заключит части выражения в скобки. Какие выводы? Думаю, следующие:
- Не стоит полагаться на порядок выполнения выражения. Строго говоря, в общем случае он не регламентирован. Если есть сомнения - используйте скобки.
- Оператор "@" нарушает оптимизацию внутри опкодов. По сути, он замедляет исполнение программы, так что лучше его не использовать - и, как видите, не только потому, что он подавляет ошибки.

P.S. не помещаю ответ в спойлер, так как все участники согласились с его необходимостью.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
LIME
Отправлено: 26 Сентября, 2013 - 10:17:05
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




EuGen спасибо...весьма познавательно
 
 Top
SAD
Отправлено: 26 Сентября, 2013 - 10:17:16
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2508
Дата рег-ции: Май 2009  
Откуда: Днепропетровск, Украина


Помог: 75 раз(а)




Мой последний пост был как раз про это Ассоциативность и приоритет =)

Но не смог так красиво расписать

(Отредактировано автором: 26 Сентября, 2013 - 10:18:36)

 
 Top
caballero
Отправлено: 26 Сентября, 2013 - 10:22:38
Post Id


Активный участник


Покинул форум
Сообщений всего: 5998
Дата рег-ции: Сент. 2011  
Откуда: Харьков


Помог: 126 раз(а)




Цитата:
Если есть сомнения - используйте скобки.

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

Цитата:
наиболее правильные мысли были выражены Ильёй (DeepVarvar) и caballero (к сожалению, не знаю имени).


Леонид, если кому интересно Улыбка

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

Тема закрыта! Продолжение в теме "Вопрос к программистам - 2".


-----
Бесплатная система складского учета с открытым кодом https://zippy[dot]com[dot]ua/zstore
 
 Top
EuGen Администратор
Отправлено: 26 Сентября, 2013 - 10:29:26
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Перенесено из темы "Вопрос к программистам"
SAD
Суть как раз в том, что это здесь никак не решает вопрос. То есть не даёт на него ответ.

Всем участникам - прошу прощения. Введена некоторая настройка конференции, ограничивающая число сообщений в теме, после чего создётся её "продолжение". Зачем это нужно - я не знаю. И я не смог пока что договориться об этом с владельцами сервера, но это очень мешает.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
imya
Отправлено: 26 Сентября, 2013 - 10:36:14
Post Id



Участник


Покинул форум
Сообщений всего: 1472
Дата рег-ции: Сент. 2012  
Откуда: Запорожье, Украина


Помог: 19 раз(а)




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

EuGen, спасибо Вам за развёрнутый ответ.


-----
PHP:
скопировать код в буфер обмена
  1. do {box != cat;} while (cat != box);


Когда нормальный человек, уезжая из дома одевает на жену пояс верности, веб-дизайнер ставит на нее счетчик...
 
My status
 Top
ALEN Модератор
Отправлено: 26 Сентября, 2013 - 10:43:02
Post Id



Участник


Покинул форум
Сообщений всего: 1459
Дата рег-ции: Авг. 2008  
Откуда: Крым


Помог: 11 раз(а)




Перенесено из темы "Вопрос к программистам"
http://lurkmore[dot]to/%2B%2Bi_%2B_%2B%2Bi

Тема закрыта! Продолжение в теме "Вопрос к программистам - 2".
Тема закрыта!
 
 Top
Страниц (9): « 1 2 3 4 5 6 7 8 [9]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Прочее »


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



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB