c# .net string performance is-empty

c# - ¿Por qué String.IsNullOrEmpty es más rápido que String.Length?



.net performance (7)

Creo que es imposible que IsNullOrEmpty sea ​​más rápido porque, como el resto dice, también hace una comprobación de nulo. Pero más rápido o no, la diferencia va a ser tan pequeña, que esto le da una ventaja al usar IsNullOrEmpty solo por esta comprobación nula adicional que hace que su código sea más seguro.

ILSpy muestra que String.IsNullOrEmpty se implementa en términos de String.Length . Pero entonces, ¿por qué String.IsNullOrEmpty(s) más rápido que s.Length == 0 ?

Por ejemplo, es un 5% más rápido en este punto de referencia:

var stopwatches = Enumerable.Range(0, 4).Select(_ => new Stopwatch()).ToArray(); var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,STU,V,W,X,Y,Z,".Split('',''); var testers = new Func<string, bool>[] { s => s == String.Empty, s => s.Length == 0, s => String.IsNullOrEmpty(s), s => s == "" }; int count = 0; for (int i = 0; i < 10000; ++i) { stopwatches[i % 4].Start(); for (int j = 0; j < 1000; ++j) count += strings.Count(testers[i % 4]); stopwatches[i % 4].Stop(); }

(Otros puntos de referencia muestran resultados similares. Esto minimizó el efecto de la ejecución de cruft en mi computadora. Además, aparte de eso, las pruebas en comparación con cadenas vacías resultaron ser aproximadamente un 13% más lentas que IsNullOrEmpty ).

Además, ¿por qué IsNullOrEmpty solo es más rápido en x86, mientras que en x64 String.Length es aproximadamente un 9% más rápido?

Actualización: detalles de la configuración de prueba: .NET 4.0 ejecutándose en Windows 7 de 64 bits, procesador Intel Core i5, proyecto de consola compilado con "Optimización de código" habilitado. Sin embargo, también se habilitó "Suprimir la optimización de JIT en la carga del módulo" (ver respuesta aceptada y comentarios).

Con la optimización completamente habilitada, la Length es aproximadamente un 14% más rápida que IsNullOrEmpty con el delegado y otros gastos generales eliminados, como en esta prueba:

var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,,STU,V,,W,,X,,,Y,,Z,".Split('',''); int count = 0; for (uint i = 0; i < 100000000; ++i) count += strings[i % 32].Length == 0 ? 1 : 0; // Replace Length test with String.IsNullOrEmpty


Creo que tu prueba no es correcta:

Esta prueba muestra que string.IsNullOrEmpty siempre es más lento que s.Length==0 porque realiza una comprobación nula adicional:

var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,STU,V,W,X,Y,Z,".Split('',''); var testers = new Func<string, bool>[] { s => s == String.Empty, s => s.Length == 0, s => String.IsNullOrEmpty(s), s => s == "" , }; int n = testers.Length; var stopwatches = Enumerable.Range(0, testers.Length).Select(_ => new Stopwatch()).ToArray(); int count = 0; for(int i = 0; i < n; ++i) { // iterate testers one by one Stopwatch sw = stopwatches[i]; var tester = testers[i]; sw.Start(); for(int j = 0; j < 10000000; ++j) // increase this count for better precision count += strings.Count(tester); sw.Stop(); } for(int i = 0; i < testers.Length; i++) Console.WriteLine(stopwatches[i].ElapsedMilliseconds);

Resultados:

6573 5328 5488 6419

Puede usar s.Length==0 cuando esté seguro de que los datos de destino no contienen cadenas nulas. En otros casos, te sugiero que uses el String.IsNullOrEmpty .


En CLR a través de CSharp capítulo 10 "Propiedades" Jeff Richter escribe:

Un método de propiedad puede tardar mucho tiempo en ejecutarse; El acceso al campo siempre se completa de inmediato. Una razón común para usar las propiedades es realizar la sincronización de subprocesos, que puede detener el subproceso para siempre, y por lo tanto, no se debe usar una propiedad si se requiere la sincronización de subprocesos. En esa situación, se prefiere un método. Además, si se puede acceder a su clase de forma remota (por ejemplo, su clase se deriva de System.MarshalByRefObject ), llamar al método de propiedad será muy lento y, por lo tanto, se prefiere un método a una propiedad. En mi opinión, las clases derivadas de MarshalByRefObject nunca deben usar propiedades.

Entonces, si vemos que String.Length es propiedad y String.IsNullOrEmpty es un método que puede ejecutarse más rápido que la propiedad String.Length .


Es porque ejecutó su punto de referencia desde Visual Studio, lo que evita que el compilador JIT optimice el código. Sin optimizaciones, este código se produce para String.IsNullOrEmpty

00000000 push ebp 00000001 mov ebp,esp 00000003 sub esp,8 00000006 mov dword ptr [ebp-8],ecx 00000009 cmp dword ptr ds:[00153144h],0 00000010 je 00000017 00000012 call 64D85BDF 00000017 mov ecx,dword ptr [ebp-8] 0000001a call 63EF7C0C 0000001f mov dword ptr [ebp-4],eax 00000022 movzx eax,byte ptr [ebp-4] 00000026 mov esp,ebp 00000028 pop ebp 00000029 ret

y ahora compáralo con el código producido para Length == 0

00000000 push ebp 00000001 mov ebp,esp 00000003 sub esp,8 00000006 mov dword ptr [ebp-8],ecx 00000009 cmp dword ptr ds:[001E3144h],0 00000010 je 00000017 00000012 call 64C95BDF 00000017 mov ecx,dword ptr [ebp-8] 0000001a cmp dword ptr [ecx],ecx 0000001c call 64EAA65B 00000021 mov dword ptr [ebp-4],eax 00000024 cmp dword ptr [ebp-4],0 00000028 sete al 0000002b movzx eax,al 0000002e mov esp,ebp 00000030 pop ebp 00000031 ret

Puede ver, que el código para Length == 0 hace todo lo que hace el código para String.IsNullOrEmpty , pero adicionalmente intenta algo así como volver a convertir booleanamente el valor booleano (devuelto de la comparación de longitud) a boolean y esto lo hace más lento que String.IsNullOrEmpty .

Si compila un programa con las optimizaciones habilitadas (Modo de lanzamiento) y ejecuta el archivo .exe directamente desde Windows, el código generado por el compilador JIT es mucho mejor. Para String.IsNullOrEmpty es:

001f0650 push ebp 001f0651 mov ebp,esp 001f0653 test ecx,ecx 001f0655 je 001f0663 001f0657 cmp dword ptr [ecx+4],0 001f065b sete al 001f065e movzx eax,al 001f0661 jmp 001f0668 001f0663 mov eax,1 001f0668 and eax,0FFh 001f066d pop ebp 001f066e ret

y para Longitud == 0 :

001406f0 cmp dword ptr [ecx+4],0 001406f4 sete al 001406f7 movzx eax,al 001406fa ret

Con este código, los resultados son los esperados, es decir, la longitud == 0 es ligeramente más rápida que String.IsNullOrEmpty .

También vale la pena mencionar que usar Linq, las expresiones lambda y el módulo de cómputo en su punto de referencia no es una buena idea, ya que estas operaciones son lentas (en comparación con la comparación de cadenas) y hacen que el punto de referencia sea inexacto.


Su punto de referencia no mide String.IsNullOrEmpty vs String.Length, sino cómo se generan las diferentes expresiones lambda para las funciones. Es decir, no es muy sorprendente que el delegado que solo contiene la función de llamada única (IsNullOrEmpty) sea más rápido que uno con función de llamada y comparación (Longitud == 0).

Para obtener una comparación de llamada activa, escriba el código que los llama directamente sin delegados.

EDITAR: Mis medidas aproximadas muestran que la versión delegada con IsNullOrEmpty es un poco más rápida que el resto, mientras que las llamadas directas a la misma comparación están en orden inverso (y casi dos veces más rápido debido a un número significativamente menor de código adicional) en mi máquina. Los resultados pueden desconfiar entre máquinas, modo x86 / x64, así como entre versiones de tiempo de ejecución. Por motivos prácticos, consideraría que las 4 formas son casi las mismas si necesita usarlas en las consultas LINQ.

En general, dudo que haya una diferencia mensurable en el programa real elegido por estos métodos, así que elija el que le resulte más legible y utilícelo. Generalmente prefiero IsNullOrEmpty ya que da menos oportunidad de obtener == /! = Incorrecto en una condición.

La eliminación de la manipulación de la cadena por completo desde el momento en que el código crítico probablemente generará una gran ventaja, ya que elegir entre estas opciones, y eliminar LINQ para el código crítico es una opción. Como siempre, asegúrese de medir la velocidad general del programa en el escenario de la vida real.


Tu prueba está mal en alguna parte. IsNullOrEmpty no puede ser más rápido por definición, ya que realiza una operación de comparación nula adicional y luego prueba la Longitud.

Entonces la respuesta puede ser: es más rápido debido a tu prueba. Sin embargo, incluso su código muestra que IsNullOrEmpty es sistemáticamente más lento en mi máquina en los modos x86 y x64.


puede ser causada por los tipos de las variables involucradas. * Vacío parece utilizar un valor booleano, longitud un int (supongo).

Paz !

  • : editar