TL; DR En un viejo rakudo, .decode
es aproximadamente 100 veces más rápido.
En forma más larga para que coincida con su código:
sub fileToCorrectUTF8Str ($fileName) { # binary file
slurp($fileName, :bin).decode
}
Notas de rendimiento
Primero, esto es lo que escribí para probar:
# Create million and 1 bytes long file:
spurt 'foo', "1234\n6789\n" x 1e5 ~ 'Z', :bin;
# (`say` the last character to check work is done)
say .decode.substr(1e6) with slurp 'foo', :bin;
# fileToCorrectUTF8Str 'foo' );
say now - INIT now;
En el rakudo de 2018.12
TIO.run, lo anterior .decode
pesa aproximadamente .05
segundos por millón de archivos de bytes en lugar de aproximadamente 5
segundos para su solución.
Por supuesto, podría / debería probar en su sistema y / o usar versiones posteriores de rakudo. Esperaría que la diferencia permanezca en el mismo orden, pero que los tiempos absolutos mejoren notablemente a medida que pasan los años.[1]
¿Por qué es 100 veces más rápido?
Bueno, en primer lugar, @
en un Buf
/ Blob
explícitamente fuerzas Raku para ver el antiguo artículo unitario ( una memoria intermedia) como plural cosa (una lista de elementos aka de varios artículos s ). Eso significa iteración de alto nivel que, para un búfer de un millón de elementos, es inmediatamente un millón de iteraciones / operaciones de alto nivel en lugar de una sola operación de alto nivel.
En segundo lugar, el uso .decode
no solo evita la iteración sino que también incurre en una sobrecarga de llamadas al método relativamente lenta una vez por archivo, mientras que al iterar hay potencialmente un millón de .chr
llamadas por archivo. Las llamadas a métodos están (al menos semánticamente) enlazadas tarde, lo que en principio es relativamente costoso en comparación con, por ejemplo, llamar a un sub en lugar de un método (los subs generalmente están enlazados anticipadamente ).
Todo eso dijo:
Recuerde Caveat Empty [1] . Por ejemplo, las clases estándar de rakudo generan cachés de métodos, y es posible que el compilador simplemente alinee el método de todos modos, por lo que es posible que haya una sobrecarga insignificante para el aspecto de la llamada al método.
Consulte también la página de rendimiento del documento , especialmente Usar código de alto rendimiento existente .
¿Es el Buf.Str
mensaje de error LTA ?
Actualización Ver el comentario de Liz ++.
Si intenta usar .Str
un Buf
o Blob
(o equivalente, como usar el ~
prefijo) obtendrá una excepción. Actualmente el mensaje es:
Cannot use a Buf as a string, but you called the Str method on it
El documento para .Str
en Buf
/Blob
actualmente dice:
Para convertir a un Str necesitas usar .decode
.
Podría decirse que es LTA que el mensaje de error no sugiere lo mismo.
Por otra parte, antes de decidir qué hacer con respecto a esto, en todo caso, debemos considerar qué y cómo la gente podría aprender de cualquier cosa que salga mal, incluidas las señales al respecto, como los mensajes de error, y también qué y cómo lo hacen en Actualmente aprendemos y sesgamos nuestras reacciones hacia la construcción de la cultura y la infraestructura adecuadas .
En particular, si la gente puede conectarse fácilmente entre un mensaje de error que ven y una discusión en línea que lo desarrolla, eso debe tenerse en cuenta y tal vez alentarse y / o facilitarse.
Por ejemplo, ahora hay un SO que cubre este problema con el mensaje de error, por lo que es probable que un google encuentre a alguien aquí. Apoyarse en eso bien podría ser un camino más apropiado hacia adelante que cambiar el mensaje de error. O tal vez no. El cambio sería fácil ...
Considere comentar a continuación y / o buscar problemas de rakudo existentes para ver si Buf.Str
se está considerando la mejora del mensaje de error y / o si desea abrir un problema para proponer que se modifique. Cada roca que se mueve es al menos un gran ejercicio y, a medida que nuestro esfuerzo colectivo se vuelve cada vez más sabio, mejora (nuestra visión de) la montaña .
Notas al pie
[1] Como dice el conocido refrán latino Caveat Empty , el rendimiento tanto absoluto como relativo de cualquier característica de raku en particular, y más generalmente de cualquier código en particular, siempre está sujeto a variación debido a factores que incluyen las capacidades del sistema, su carga durante el tiempo que es ejecutando el código, y cualquier optimización realizada por el compilador. Así, por ejemplo, si su sistema está "vacío", entonces su código puede ejecutarse más rápido. O, como otro ejemplo, si espera un año o tres para que el compilador se acelere , los avances en el rendimiento de rakudo continúan siendo prometedores .
slurp
es solo un contenedor paraIO::Path.slurp
en este caso, por lo que llamar en su.IO.slurp
lugar hace que sea aproximadamente un 2% más rápido en mis puntos de referencia. Si extrae el archivo:enc<latin1>
, terminará con un búfer de caracteres como lo haría con la codificación UTF-8 predeterminada, pero omita las comprobaciones de si el archivo extraído es realmente UTF-8 válido que está haciendo al decodificar a una cadena UTF-8 de todos modos, lo que hace que sea aproximadamente un 10% más rápido también.