parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

Расход памяти SWITCH vs IF

nkostya 06.12.2022 11:40

Тестировал на 3.4.6 под linux. Сборка с сайта.


Старый код:
##############################################################################
@static:prepare_value[sType;uData]
	^switch[$sType]{
		^case[double]{
			^rem{ *** храним double в виде форматированной строки,
				      т.к. возникают проблемы с округлением при передаче
				      значения без круглых скобок *** }
			$result[^uData.replace[,;.]]
			$result(^result.double[])
			$result[^result.format[%f]]
			$result[^result.match[(?:\.0+|(\.\d+?)0+)^$][]{$match.1}]
		}
		^case[int]{
			$result(^uData.int[])
		}
		^case[bool]{
			$result(^uData.bool[])
		}
		^case[date;datetime]{
			^switch[$uData.CLASS_NAME]{
				^case[hash]{
					^if(def $uData.year || def $uData.month || def $uData.day || def $uData.hour || def $uData.minute){
						$result[^date::create(^if(^uData.year.int($_now.year) > 99){^uData.year.int($_now.year)}{^math:floor($_now.year / 100)^eval(^uData.year.int(0))[%02.0f]};^uData.month.int($_now.month);^uData.day.int($_now.day);^uData.hour.int(0);^uData.minute.int(0);^uData.second.int(0))]
					}{
						$result[]
					}
				}
				^case[string]{
					^rem{ *** для пустых дат создавать пустое значение *** }
					^if($uData eq "0000-00-00 00:00:00" || $uData eq "0000-00-00"){
						$result[]
					}{
						^if(^uData.double(0)){
							$result[^date::create($uData)]
						}{
							$result[^date::create[$uData]]
						}
					}
				}
				^case[DEFAULT]{
					$result[^date::create[$uData]]
				}
			}
		}
		^case[DEFAULT]{
			$result[$uData]
		}
	}
#end @prepare_value[]
Новй код:
##############################################################################
@static:prepare_value[iType;uData]
	^if($iType == 3){
		^rem{ *** храним double в виде форматированной строки,
			      т.к. возникают проблемы с округлением при передаче
			      значения без круглых скобок *** }
		$result[^uData.replace[,;.]]
		$result(^result.double[])
		$result[^result.format[%f]]
		$result[^result.match[(?:\.0+|(\.\d+?)0+)^$][]{$match.1}]
	}($iType == 2){
		$result(^uData.int[])
	}($iType == 1){
		$result(^uData.bool[])
	}($iType == 4){
		^switch[$uData.CLASS_NAME]{
			^case[hash]{
				^if(def $uData.year || def $uData.month || def $uData.day || def $uData.hour || def $uData.minute){
					$result[^date::create(^if(^uData.year.int($_now.year) > 99){^uData.year.int($_now.year)}{^math:floor($_now.year / 100)^eval(^uData.year.int(0))[%02.0f]};^uData.month.int($_now.month);^uData.day.int($_now.day);^uData.hour.int(0);^uData.minute.int(0);^uData.second.int(0))]
				}{
					$result[]
				}
			}
			^case[string]{
				^rem{ *** для пустых дат создавать пустое значение *** }
				^if($uData eq "0000-00-00 00:00:00" || $uData eq "0000-00-00"){
					$result[]
				}{
					^if(^uData.double(0)){
						$result[^date::create($uData)]
					}{
						$result[^date::create[$uData]]
					}
				}
			}
			^case[DEFAULT]{
				$result[^date::create[$uData]]
			}
		}
	}{
		$result[$uData]
	}
#end @prepare_value[]
В целом логика кода одна и таже. Только switch заменен на if
sType замененный на iType существенно не влияет.

Как проверялось:
	$data[^for[](0;1000){a}]
	
	$self.field[^DBField::create[
		$.type[string]
		$.name[data]
	]]

^Rusage:measure[stat]{
	^for[i](0;100000){
		^self.do[$data]
	}
}


##############################################################################
@do[data]
#	$data_[$data]
	$data_[^self.field.init[$data]]
#end @do[]
Смотрим на memory:used.

В случае если в do просто передавать строку, то расход примерно 8 МБ.

Если использовать prepare_value со switch, то расход 70МБ (!!!!).
Если заменить switch на if, то расход 8 МБ.

Что за фантастика со switch?


Если вопрос по allocated_since_start, есть ли варианты его оптимизировать?

для присвоения строке - allocated_since_start = 22МБ
при использовании switch - 198МБ
при использовании if - 140МБ

Если вынести метод из Класса, то
switch - allocated_since_start - 162 МБ
if - allocated_since_start - 106 МБ

Такой большой allocated_since_start для такого вызова это нормально?