ruby - example - updatemany mongodb
obj.nil? vs. obj== nil (7)
¿Es mejor usar obj.nil?
u obj == nil
y obj == nil
son los beneficios de ambos?
¿Es mejor usar obj.nil? u obj == nil
Es exactamente lo mismo. Tiene exactamente los mismos efectos observables desde el exterior (pfff) *
y cuales son los beneficios de ambos.
Si te gustan las micro optimizaciones, todos los objetos volverán false
al .nil?
mensaje, excepto para el objeto nil
sí, mientras que el objeto que usa el mensaje ==
realizará una pequeña comparación micro con el otro objeto para determinar si es el mismo objeto.
* Ver comentarios.
En muchos casos, ninguno, solo prueba el valor de verdad booleano
Aunque las dos operaciones son muy diferentes, estoy bastante seguro de que siempre producirán el mismo resultado, al menos hasta que alguien en el borde de algo decida anular el #nil?
de #nil?
método. (Uno llama al método #nil?
de Object o reemplazado en NilClass
y uno se compara con el singleton nil
).
Sugeriría que, en caso de duda, haga una tercera vía, en realidad, y simplemente pruebe el valor de verdad de una expresión.
Entonces, if x
y no if x == nil
o if x.nil?
, para tener este DTRT de prueba cuando el valor de la expresión es falso . Trabajar de esta manera también puede ayudar a evitar que alguien FalseClass#nil?
a definir FalseClass#nil?
como cierto
Dejando a un lado la sintaxis y el estilo, quería ver cómo eran "los mismos" varios enfoques para probar el nulo. Entonces, escribí algunos puntos de referencia para ver, y arrojé varias formas de prueba nula.
TL; DR - Resultados primero
Los resultados reales mostraron que el uso de obj
como un control nulo es el más rápido en todos los casos. obj
es consistentemente más rápido en un 30% o más que revisar obj.nil?
.
Sorprendentemente, obj
realiza aproximadamente 3 o 4 veces más rápido que las variaciones en obj == nil
, por lo que parece haber una penalización de rendimiento punitiva.
¿Quiere acelerar su algoritmo de rendimiento intensivo en un 200% -300%? Convertir todos los obj == null
cheques obj == null
a obj
. ¿Quieres sacarle provecho al rendimiento de tu código? Usa obj == null
todas partes que puedas. (Sólo bromeaba: ¡no pongas a prueba tu código!).
En el análisis final, utilice siempre obj
. Eso concuerda con la regla de la Guía de estilo de Ruby : no hagas verificaciones explícitas no nulas a menos que estés tratando con valores booleanos.
Las condiciones de referencia
De acuerdo, esos son los resultados, entonces, ¿cómo se reúne este punto de referencia, qué pruebas se realizaron y cuáles son los detalles de los resultados?
Los cheques nulos que se me ocurrieron son:
- obj
- obj.nil?
- ! obj
- !! obj
- obj == nil
- obj! = nil
Escogí varios tipos de Ruby para probar, en caso de que los resultados cambiaran según el tipo. Estos tipos fueron Fixnum, Float, FalseClass, TrueClass, String y Regex
Utilicé estas condiciones de verificación nula en cada uno de los tipos para ver si había una diferencia entre ellos, en cuanto al rendimiento. Para cada tipo, probé objetos nulos y objetos de valor no nulo (por ejemplo, 1_000_000
, 100_000.0
, false
, true
, "string"
y //w/
) para ver si hay una diferencia en la comprobación de nil en un objeto eso es nulo en un objeto que no es nulo.
Los puntos de referencia
Con todo eso fuera del camino, aquí está el código de referencia:
require ''benchmark''
nil_obj = nil
N = 10_000_000
puts RUBY_DESCRIPTION
[1_000_000, 100_000.0, false, true, "string", //w/].each do |obj|
title = "#{obj} (#{obj.class.name})"
puts "============================================================"
puts "Running tests for obj = #{title}"
Benchmark.bm(15, title) do |x|
implicit_obj_report = x.report("obj:") { N.times { obj } }
implicit_nil_report = x.report("nil_obj:") { N.times { nil_obj } }
explicit_obj_report = x.report("obj.nil?:") { N.times { obj.nil? } }
explicit_nil_report = x.report("nil_obj.nil?:") { N.times { nil_obj.nil? } }
not_obj_report = x.report("!obj:") { N.times { !obj } }
not_nil_report = x.report("!nil_obj:") { N.times { !nil_obj } }
not_not_obj_report = x.report("!!obj:") { N.times { !!obj } }
not_not_nil_report = x.report("!!nil_obj:") { N.times { !!nil_obj } }
equals_obj_report = x.report("obj == nil:") { N.times { obj == nil } }
equals_nil_report = x.report("nil_obj == nil:") { N.times { nil_obj == nil } }
not_equals_obj_report = x.report("obj != nil:") { N.times { obj != nil } }
not_equals_nil_report = x.report("nil_obj != nil:") { N.times { nil_obj != nil } }
end
end
Los resultados
Los resultados fueron interesantes, porque el rendimiento de los tipos Fixnum, Float y String fue prácticamente idéntico, Regex casi así, y FalseClass y TrueClass se realizaron mucho más rápidamente. Las pruebas se realizaron en las versiones de MRI 1.9.3, 2.0.0, 2.1.5 y 2.2.5 con resultados comparativos muy similares en todas las versiones. Los resultados de la versión MRI 2.2.5 se muestran aquí (y están disponibles en la página principal :
ruby 2.2.5p319 (2016-04-26 revision 54774) [x86_64-darwin14]
============================================================
Running tests for obj = 1000000 (Fixnum)
user system total real
obj: 0.970000 0.000000 0.970000 ( 0.987204)
nil_obj: 0.980000 0.010000 0.990000 ( 0.980796)
obj.nil?: 1.250000 0.000000 1.250000 ( 1.268564)
nil_obj.nil?: 1.280000 0.000000 1.280000 ( 1.287800)
!obj: 1.050000 0.000000 1.050000 ( 1.064061)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.170393)
!!obj: 1.110000 0.000000 1.110000 ( 1.122204)
!!nil_obj: 1.120000 0.000000 1.120000 ( 1.147679)
obj == nil: 2.110000 0.000000 2.110000 ( 2.137807)
nil_obj == nil: 1.150000 0.000000 1.150000 ( 1.158301)
obj != nil: 2.980000 0.010000 2.990000 ( 3.041131)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.203015)
============================================================
Running tests for obj = 100000.0 (Float)
user system total real
obj: 0.940000 0.000000 0.940000 ( 0.947136)
nil_obj: 0.950000 0.000000 0.950000 ( 0.986488)
obj.nil?: 1.260000 0.000000 1.260000 ( 1.264953)
nil_obj.nil?: 1.280000 0.000000 1.280000 ( 1.306817)
!obj: 1.050000 0.000000 1.050000 ( 1.058924)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.096747)
!!obj: 1.100000 0.000000 1.100000 ( 1.105708)
!!nil_obj: 1.120000 0.010000 1.130000 ( 1.132248)
obj == nil: 2.140000 0.000000 2.140000 ( 2.159595)
nil_obj == nil: 1.130000 0.000000 1.130000 ( 1.151257)
obj != nil: 3.010000 0.000000 3.010000 ( 3.042263)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.189145)
============================================================
Running tests for obj = false (FalseClass)
user system total real
obj: 0.930000 0.000000 0.930000 ( 0.933712)
nil_obj: 0.950000 0.000000 0.950000 ( 0.973776)
obj.nil?: 1.250000 0.000000 1.250000 ( 1.340943)
nil_obj.nil?: 1.270000 0.010000 1.280000 ( 1.282267)
!obj: 1.030000 0.000000 1.030000 ( 1.039532)
!nil_obj: 1.060000 0.000000 1.060000 ( 1.068765)
!!obj: 1.100000 0.000000 1.100000 ( 1.111930)
!!nil_obj: 1.110000 0.000000 1.110000 ( 1.115355)
obj == nil: 1.110000 0.000000 1.110000 ( 1.121403)
nil_obj == nil: 1.100000 0.000000 1.100000 ( 1.114550)
obj != nil: 1.190000 0.000000 1.190000 ( 1.207389)
nil_obj != nil: 1.140000 0.000000 1.140000 ( 1.181232)
============================================================
Running tests for obj = true (TrueClass)
user system total real
obj: 0.960000 0.000000 0.960000 ( 0.964583)
nil_obj: 0.970000 0.000000 0.970000 ( 0.977366)
obj.nil?: 1.260000 0.000000 1.260000 ( 1.265229)
nil_obj.nil?: 1.270000 0.010000 1.280000 ( 1.283342)
!obj: 1.040000 0.000000 1.040000 ( 1.059689)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.068290)
!!obj: 1.120000 0.000000 1.120000 ( 1.154803)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.155932)
obj == nil: 1.100000 0.000000 1.100000 ( 1.102394)
nil_obj == nil: 1.130000 0.000000 1.130000 ( 1.160324)
obj != nil: 1.190000 0.000000 1.190000 ( 1.202544)
nil_obj != nil: 1.200000 0.000000 1.200000 ( 1.200812)
============================================================
Running tests for obj = string (String)
user system total real
obj: 0.940000 0.000000 0.940000 ( 0.953357)
nil_obj: 0.960000 0.000000 0.960000 ( 0.962029)
obj.nil?: 1.290000 0.010000 1.300000 ( 1.306233)
nil_obj.nil?: 1.240000 0.000000 1.240000 ( 1.243312)
!obj: 1.030000 0.000000 1.030000 ( 1.046630)
!nil_obj: 1.060000 0.000000 1.060000 ( 1.123925)
!!obj: 1.130000 0.000000 1.130000 ( 1.144168)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.147330)
obj == nil: 2.320000 0.000000 2.320000 ( 2.341705)
nil_obj == nil: 1.100000 0.000000 1.100000 ( 1.118905)
obj != nil: 3.040000 0.010000 3.050000 ( 3.057040)
nil_obj != nil: 1.150000 0.000000 1.150000 ( 1.162085)
============================================================
Running tests for obj = (?-mix:/w) (Regexp)
user system total real
obj: 0.930000 0.000000 0.930000 ( 0.939815)
nil_obj: 0.960000 0.000000 0.960000 ( 0.961852)
obj.nil?: 1.270000 0.000000 1.270000 ( 1.284321)
nil_obj.nil?: 1.260000 0.000000 1.260000 ( 1.275042)
!obj: 1.040000 0.000000 1.040000 ( 1.042543)
!nil_obj: 1.040000 0.000000 1.040000 ( 1.047280)
!!obj: 1.120000 0.000000 1.120000 ( 1.128137)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.138988)
obj == nil: 1.520000 0.010000 1.530000 ( 1.529547)
nil_obj == nil: 1.110000 0.000000 1.110000 ( 1.125693)
obj != nil: 2.210000 0.000000 2.210000 ( 2.226783)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.169347)
Me encuentro sin usar .nil?
en absoluto cuando puedes hacer:
unless obj
// do work
end
En realidad es más lento usar .nil?
pero no notablemente. .nil?
es solo un método para verificar si ese objeto es igual a nulo, aparte del atractivo visual y el escaso rendimiento que toma no hace ninguna diferencia.
Personalmente, prefiero object.nil?
ya que puede ser menos confuso en líneas más largas; Sin embargo, también suelo usar object.blank?
si estoy trabajando en Rails ya que eso también comprueba si la variable está vacía.
Puedes usar Symbol # to_proc en nil?
, mientras que no sería práctico en x == nil
.
arr = [1, 2, 3]
arr.any?(&:nil?) # Can be done
arr.any?{|x| x == nil} # More verbose, and I suspect is slower on Ruby 1.9.2
! arr.all? # Check if any values are nil or false
Some podrían sugerir que usar .nil? es más lento que la comparación simple, lo que tiene sentido cuando lo piensas.
Pero si la escala y la velocidad no son su preocupación, entonces .nil? quizás sea más legible.