Nitpicking: сохранение Tcl в переменной или нет, для скорости, в процедурах

Это что-то общего вопроса. Предполагая TCL 8.6, давайте скажем, что у меня довольно короткая процедура. У меня есть 2 способа возврата стоимости процентов:
1. Использовать стандартную практику кода if/else, сохранить в переменной и вернуть значение переменной. Например:

proc me { gop goo } {
   if { [ lomsa $gop ] {
      set ret [ foo $goo $gop ]
   } else {
      set ret [ bar $gop $goo ]
   }
   return $ret
}

2. использовать троичный аргумент и, по сути, не иметь процедуры без добавленной закрытой переменной (то есть используются только аргументы). Результатом троичного выражения является то, что возвращает значение. Например:

proc me { gop goo } {
   expr { [ lomsa $gop ] ? [ foo $goo $gop ] : [ bar $gop $goo ] }
}

Некоторые члены моей команды считают, что читаемость лучше, чем немного лучше в пункте 1.
Я не могу получить доступ к движку псевдокода в моей настройке TCL (это оболочка от поставщика), но я предполагаю, что разница в коде и его производительности будет, но незначительной, если вообще будет. Т.е. процедура должна хранить возвращаемое где-то значение. Сколько стоит регистрация определенной переменной для нее, а не просто для сохранения ее в качестве возвращаемого значения?
Вопрос может быть расширен, например, для операторов switch. Применяются те же правила. Оператор switch может быть сохранен в переменной, а затем, после переключения, возвращается значение переменной, или оператор switch просто возвращает значение, не сохраняя его в переменной. Кроме того, перед возвращаемой частью может быть расширенный код. Перечисленная выше процедура - это то, что они называют "удобной процедурой"
Вы можете предположить, что производительность представляет большой интерес для кода.

4 ответа

Решение

Помимо читабельности, троичный оператор может давать неожиданные результаты. Например, если выбранная процедура возвращает 0123, ваша процедура будет вместо 83. Поэтому, если вы не уверены, что ситуация никогда не произойдет, безопаснее использовать команду if.

В случае сомнений не угадывайте; time Это!

Для вашего примера кода разница в производительности находится в пределах пары процентов для самых тривиальных реализаций lomsa, foo а также bar что мне может сойти с рук (и при том понимании, что есть некоторые незначительные технические различия в нескольких крайних случаях). Для чего-то более сложного вы находитесь в шуме, поскольку вы балансируете стоимость доступа к локальной переменной с дополнительным вызовом кода операции, который преобразует значения в числовые значения, если это возможно, и именно то, что медленнее, это территория "зависит",

switch оператор, когда он имеет дело со случаями, которые он может компилировать вообще, использует стек оценки Tcl в качестве временного хранилища. Если бы я снова написал компиляцию байт-кода, я бы, вероятно, использовал временную локальную переменную (они безымянные; вы не можете прикасаться к ним из своего кода), чтобы упростить некоторые другие вычисления. Чтобы узнать, какой вариант является самым быстрым, оцените фактический код; синхронизация некоторого прокси-кода, который является менее сложным, может легко дать противоположные выводы.

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

Скомпилированные в байт-код, две версии команды не очень отличаются: в обоих случаях структура выбора преобразуется в инструкции перехода.

Чтобы примерно увидеть, как ваш код будет выглядеть скомпилированным и готовым к запуску, используйте tcl::unsupported::disassemble proc <name-of-proc>, Некоторые предостережения: команда не поддерживается, что означает, что она не гарантированно будет работать так, как вы ожидаете, или будет работать так же, как сейчас в будущих выпусках. Просмотр списка разборки также может вводить в заблуждение, если вы не очень хорошо знаете, как работает интерпретатор байт-кода.

Чтобы узнать больше о производительности, вы должны вместо этого взглянуть на time командование и bench пакет, который очень полезен для измерения производительности.

Документация: скамья (пакет), время

Что насчет середины?

proc me { gop goo } {
   if { [lomsa $gop] } {
      foo $goo $gop
   } else {
      bar $gop $goo
   }
}

или если вам нравится явный возврат:

proc me { gop goo } {
   if { [lomsa $gop] } {
      return [foo $goo $gop]
   } else {
      return [bar $gop $goo]
   }
}
Другие вопросы по тегам