LF00
Tengo algunas matrices que almacenan los posibles parámetros para algunos comandos de impresoras 3D. Lo uso para verificar si el comando es legal. Estoy confundido acerca de dónde debo poner estas matrices. Solo se accederá a estas matrices en la función formatcheck, y la función se llamará tantas veces como haya miles de comandos para comprobar. ¿Debería ponerlos en la función de verificación de formato como variables o al comienzo de la clase en la que se encuentra la función de verificación de formato, como variables estáticas privadas?
public function checkFileGcodeFormat()
{
$Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
$Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
$Ts = array(0, 1);
if (
!(
$this->hasM()
&& $this->hasNoXYZ()
&& in_array($this->M, $this->Ms)
)
||
(
$this->hasG()
&& in_array($this->G, $this->Gs)
)
||
(
$this->hasT()
&& $this->hasNoXYZ()
&& in_array($this->T, $this->Ts)
)
)
return false;
else
return true;
}
o:
private static $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private static $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private static $Ts = array(0, 1);
...
...
public function checkFileGcodeFormat()
{
if (
!(
$this->hasM()
&& $this->hasNoXYZ()
&& in_array($this->M, $this->Ms)
)
||
(
$this->hasG()
&& in_array($this->G, $this->Gs)
)
||
(
$this->hasT()
&& $this->hasNoXYZ()
&& in_array($this->T, $this->Ts)
)
)
return false;
else
return true;
}
bwoebi
TL;DR: use una constante de clase para obtener el máximo rendimiento (ver al final de la respuesta).
Veamos las características de rendimiento de las diferentes versiones (y por qué):
PHP 5
Los arreglos en propiedades estáticas se crean en tiempo de compilación, muy rápidamente, sin la participación de la máquina virtual. Sin embargo, acceder a las propiedades estáticas es un poco más lento que acceder a las variables normales, pero aún así es mucho más rápido que recrear la matriz en cada ejecución.
Las matrices en funciones normales se vuelven a crear en tiempo de ejecución con cada ejecución, en cualquier caso. Y la creación en tiempo de ejecución en VM significa que cada elemento se agrega uno por uno, en códigos de operación individuales, lo que significa bastante sobrecarga (especialmente si la matriz es más grande que solo 1-2 elementos).
PHP 7.0
Arreglos en funciones normales [in general] se crean un poco más rápido debido a que la creación de matrices en general se acelera (optimizaciones en el manejo de HashTable). Si son todos valores constantes, se almacenan en caché en la matriz interna de valores constantes, pero se duplican en cada acceso. Sin embargo, hacer una acción de copia directa altamente especializada es obviamente más rápido que agregar elementos uno por uno a la matriz como en PHP 5.
Opcache los está marcando como INMUTABLE internamente, lo que permite el acceso directo [so you get full speed with opcache]. (Ver también https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html)
PHP 7.1
Las matrices siempre se almacenan en caché de forma nativa en la matriz interna de valores constantes, con semántica de copia en escritura.
Ahora, usar una propiedad estática es más lento, ya que buscar una propiedad estática tiene menos rendimiento que una simple escritura en una variable. [Direct access to a variable has no extra overhead.]
También tenga en cuenta que desde PHP 5.6 puede declarar constantes (de clase) con el valor de una matriz. PHP 7.1 permite la sustitución directa de constantes de clase de la misma clase y agregará la matriz directamente a la matriz de valores constantes internos para uso directo con in_array.
Es decir, el código más rápido es (con 7.1 al menos):
private const Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private const Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private const Ts = array(0, 1);
...
...
public function checkFileGcodeFormat()
{
if (! ($this->hasM() && $this->hasNoXYZ() && in_array($this->M, self::Ms)) || ($this->hasG() && in_array($this->G, self::Gs)) || ($this->hasT() && $this->hasNoXYZ() && in_array($this->T, self::Ts)) )
return false;
else
return true;
}
sevavietl
Creo que la matriz que define una propiedad tiene más sentido, ya que las matrices definidas dentro de los métodos se crean en cada llamada.
Pero quiero hacer otro punto. Si tiene matrices bastante grandes para buscar valor, es más importante cómo los estructura. Yo sugeriría esto:
array(
82 => true,
83 => true,
84 => true,
104 => true,
106 => true,
107 => true,
109 => true,
140 => true,
190 => true
);
array(
0 => true,
1 => true,
20 => true,
21 => true,
28 => true,
90 => true,
91 => true,
92 => true
);
array(
0 => true,
1 => true
);
Teniendo esta estructura puedes usar isset
(O(1)
) en vez de in_array
(O(n)
).
Aquí hay algunas otras preguntas sobre isset
contra in_array
:
-
¿Qué es más rápido: in_array o isset? [closed]
-
in_array vs isset – rendimiento
Y aquí hay algunas publicaciones con puntos de referencia:
El último es bastante antiguo, pero creo que la proporción se mantiene.
Así que para resumir. cuando usas isset
el tiempo de búsqueda es constante (en realidad puede variar, pero esto puede ignorarse). cuando usas in_array
el tiempo de búsqueda depende de la posición del elemento (y así del tamaño de la matriz). Incluso en arreglos pequeños isset
funciona más rápido
-
¡bien! mejor ahora.
– LF00
9 dic 2016 a las 21:20
-
Buen consejo (+1)… aunque no responde directamente a la pregunta en cuestión (dónde => ver mi respuesta), probablemente sea útil ya que OP usa in_array.
– bwoebi
9 dic 2016 a las 23:52
smcjones
La comida para llevar de una oración: Las constantes de clase pueden ser más rápidas, pero la memoria probablemente no importe, y usar el Inyección de dependencia Design Pattern será más flexible y eficiente en memoria.
Si bien una propiedad constante o estática de clase será más rápida que crear una matriz en una función (consulte la respuesta de bwoebi) porque está integrada en la memoria una vez y se puede acceder a ella varias veces, de ninguna manera es el método más eficiente disponible, o la forma recomendada para resolver el problema raíz que el OP pretende resolver.
Si está seguro de que ningún dato cambiará en el futuro, o si nunca va a querer usar diferentes conjuntos de datos en diferentes momentos, incluso para realizar pruebas, entonces puede salirse con la suya con este método de todos modos. . Si desea un código más flexible, las constantes de clase o las propiedades estáticas pueden causar serios problemas. Como explicaré más adelante, es poco probable que importe la cantidad de memoria utilizada o guardada. Las consideraciones más importantes son:
- ¿Qué tan fácil será modificar mi código en el futuro?
- ¿Qué tan flexible es mi código a las circunstancias cambiantes?
- ¿Qué tan fácil es probar unitariamente mi código?
Antes de comprometerse con la ruta más eficiente en memoria, asegúrese de equilibrar otras formas de eficiencia, como la eficiencia de su tiempo en el desarrollo y la depuración.
#Por qué es posible que la memoria no importe Debido a la velocidad de las computadoras modernas, el rendimiento que experimenta entre las dos versiones rara vez debería marcar la diferencia. La E/S de disco suele ser un problema más que la memoria. Si su servidor está operando en una cantidad MUY pequeña de memoria y espera un volumen muy alto, entonces la eficiencia de la memoria de su código será más importante que si tiene un volumen moderado y una memoria moderada.
Para poner las cosas en perspectiva, véase Este artículo sobre la eficiencia de las matrices en PHP. ¿La comida para llevar? Aunque las matrices de PHP5 son terriblemente ineficientes, incluso una matriz de 100.000 enteros ocupará aproximadamente 14M. Eso es MUCHO, pero considerando que el script PHP promedio tiene un límite de memoria de 128My las recomendaciones mínimas del servidor requieren alrededor de 2 GB de memoria, esto de repente se ve diferente.
Eso significa que debe preocuparse por esto si el resto de su código es ineficiente o si tiene un volumen alto en comparación con poca memoria. Eso hará que su aplicación se ralentice y/o su sistema se bloquee.
De todos modos, en una situación en la que esté explorando opciones arquitectónicas desde el principio, recomendaría encarecidamente un patrón de diseño. Es decir, el Inyección de dependencia patrón de diseño. Esto se debe a una serie de razones, incluida la flexibilidad del código y las pruebas unitarias, pero también tiene una huella de memoria amigable. Debido a esto, probablemente se consideraría una mejor práctica sobre cualquiera de las dos opciones que recomienda.
##¿Por qué no propiedades estáticas? Al principio, la ruta más fácil es usar propiedades estáticas. Sin embargo, en mi experiencia, la ruta más fácil no siempre es la mejor y, con frecuencia, puede ser la más difícil de mantener. Un problema aquí es que sus funciones/métodos probablemente llamarán a otra clase dentro. Como ejemplo, vamos a crear dos clases: MyFooClass
y DoStuff
y vea cómo podrían interactuar de forma predeterminada.
class MyFooClass
{
public static $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
public static $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
public static $Ts = array(0, 1);
}
class DoStuff
{
public function oneOfThousands()
{
$array = MyFooClass::$Gs;
//... do stuff
}
}
Ahora, si alguna vez desea insertar diferentes valores de matriz para diferentes propósitos, o si desea realizar pruebas unitarias con menos o más configuraciones, abundan las complicaciones.
###Inyección de dependencia al rescate!
Como todos los patrones de diseño, la inyección de dependencia resuelve un problema. En este caso, el problema es pasar valores de manera fácil y eficiente entre múltiples funciones/métodos sin sacrificar la flexibilidad. Usando un patrón DI básico, puede inicializar sus arreglos en propiedades no estáticas y pasar un solo objeto que contenga esta propiedad de arreglo a cada parte de su código. Eso le permitiría eliminar su preocupación por el rendimiento.
Ejemplo:
class MyFooClass
{
private $Ms, $Gs, $Ts;
public function __construct()
{
$this->Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
$this->Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
$this->Ts = array(0, 1);
}
public function checkFileGcodeFormat()
{
if (
!(
$this->hasM()
&& $this->hasNoXYZ()
&& in_array($this->M, $this->Ms)
)
||
(
$this->hasG()
&& in_array($this->G, $this->Gs)
)
||
(
$this->hasT()
&& $this->hasNoXYZ()
&& in_array($this->T, $this->Ts)
)
)
return false;
else
return true;
}
}
// DI here:
$foo = new MyFooClass();
$bar = new MyBarClass();
$bar->setArrays($foo);
//alternative DI approach - parameters in constructor
$bar = new MyBarClass($foo);
En tus MyBarClass
estás asignando un MyFooClass
objetar una propiedad $foo
. A continuación, puede llamar a cualquier método público o propiedad de este objeto con $this->foo
. Por ejemplo: $this->foo->checkFileGcodeFormat()
.
Con este patrón de diseño:
- Cuando desee desarrollar una nueva prueba unitaria, será mucho más fácil hacerlo.
- Si alguna vez desea/necesita implementar un subconjunto de Gcodes para una aplicación, simplemente pase un objeto diferente con diferentes valores de matriz.
- De manera similar, si desea probar un nuevo Gcode en una nueva clase sin introducirlo en cada parte de su secuencia de comandos, puede hacerlo.
- La memoria gastada es del tamaño de un puntero en PHP (que es lo mismo que el tamaño de un puntero en C… 8 bytes en una arquitectura de 64 bits).
##Conclusión
- Si puede, recomendaría usar el patrón de diseño de inyección de dependencia.
- Puede elegir una propiedad estática para una mejor huella de memoria (nota: esto no se excluye mutuamente de Inyección de dependencia, pero es menos importante si usa Inyección de dependencia).
- En una configuración de servidor web estándar, con tráfico moderado, es poco probable que su consumo de memoria importe, ya sea que use propiedades estáticas o llame a una matriz desde dentro de una función.
-
¿La inyección de dependencia no se vuelve un poco tonta cuando tienes un montón de cosas en la mayoría de tus clases de lógica empresarial? Es probable que todos tengan constantes de tipo de error, constantes de mensajes de registro, todo tipo de constantes. Siempre que esas clases sean básicamente contenedores de datos, parece sensato hacer referencia a ellas directamente. No parece que las clases tengan espacios de nombres y valores de datos de alojamiento que tengan ningún problema con las pruebas, etc. Dichos contenedores no son otros objetos/clases para probar. Siempre y cuando no haya cometido un error tipográfico, están perfectamente listos para comenzar.
– ahnbizcad
13 de noviembre de 2020 a las 6:22
-
Sí, esta respuesta tiene 4 años. Yo diría que, en general, estas clases tienen métodos estáticos y, por lo tanto, no tienen estado, por lo que probablemente no usaría DI de todos modos. Simplemente haga referencia a los valores de la clase estática
MyBarClass::foo()
. Si necesita crear una instancia de la clase, preguntaría por qué es un requisito y probablemente volvería a DI. Incluso una clase de registro, aunque probablemente se pueda crear una instancia, debe diseñarse con mucho cuidado para encapsularse y no inyectarse directamente.– smcjones
14 de noviembre de 2020 a las 1:42
-
Entonces, una regla general aproximada es que DI se aplica principalmente a instancias (y variables), no a clases sin estado
– ahnbizcad
24 de noviembre de 2020 a las 20:40
Si NUNCA cambian, entonces debería formatear como const
. Se hornean en tiempo de compilación y, por lo tanto, serán los más rápidos.
const MS = [82, 83, 84, 104, 106, 107, 109, 140, 190];
const GS = [0, 1, 20, 21, 28, 90, 91, 92];
const TS = [0, 1];
if (!in_array($this->M, MS)) {
...
}
o
class () {
const MS = [82, 83, 84, 104, 106, 107, 109, 140, 190];
const GS = [0, 1, 20, 21, 28, 90, 91, 92];
const TS = [0, 1];
if (!in_array($this->M, self::MS)) {
...
}
}
Algunas notas:
- constantes son como
define
pero horneado en tiempo de compilación, por lo que es un poco más rápido que las matrices definidas y variables. - puede definir const a nivel global o a nivel de clase (http://php.net/manual/en/language.oop5.constants.php). A partir de php 7.1, también puede declarar las constantes de clase como privadas/públicas/protegidas, etc.
- He usado letras mayúsculas para definir, que es un estándar no oficial, pero no un requisito.
Si realmente está buscando comprender cómo se puede medir el rendimiento del código, debe familiarizarse con la notación Big-O.
¿Qué es Big-O?
Hoja de trucos de Big-O
Aparte de eso, defínalos como propiedades base de clase protegidas para datos estáticos.
class foo
{
protected static $bar = array();
}
-
¡Apreciaremos mucho más información sobre la fecha estática preferida aquí! +1 para la hoja Big-O. ¡Gracias!
– LF00
9 de diciembre de 2016 a las 9:21
-
deberías haber dicho por qué usando propiedades estáticas? (¿puntos de referencia? ¿conocimiento sobre las partes internas?)… y Big-O no está realmente relacionado con esto…
– bwoebi
9 dic 2016 a las 16:32
JuanC
private static $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private static $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private static $Ts = array(0, 1);
public function checkFileGcodeFormat(){
if (! ($this->hasM() && $this->hasNoXYZ() && in_array($this->M, self::$Ms)) || ($this->hasG() && in_array($this->G, self::$Gs)) || ($this->hasT() && $this->hasNoXYZ() && in_array($this->T, self::$Ts)) )
return false;
else
return true;
}
-
¡Apreciaremos mucho más información sobre la fecha estática preferida aquí! +1 para la hoja Big-O. ¡Gracias!
– LF00
9 de diciembre de 2016 a las 9:21
-
deberías haber dicho por qué usando propiedades estáticas? (¿puntos de referencia? ¿conocimiento sobre las partes internas?)… y Big-O no está realmente relacionado con esto…
– bwoebi
9 dic 2016 a las 16:32
aquí es una cuestión de preferencia. pero personalmente iré configurándolo como una propiedad de clase.
– Fantasma
27 de julio de 2016 a las 3:25
¿Hay algunos problemas de rendimiento?
– LF00
27 de julio de 2016 a las 3:28
No. Pero el segundo procedimiento puede tener un poco más de tiempo de procesamiento.
– Fantasma
27 de julio de 2016 a las 3:36
NO. establecer como propiedad y llamar solo en la carga de la página O variable cada vez que el
checkFileGcodeFormat
se llama– Fantasma
27 de julio de 2016 a las 3:53
@ChrysUgwu “pero el segundo procedimiento podría tener un poco más de tiempo de procesamiento”. Medí las dos versiones y descubrí que la segunda (con propiedades estáticas) es dos veces más rápida que la primera (PHP 5.5.36)
– cske
30 de noviembre de 2016 a las 12:57