Estoy trabajando en un proyecto (database-ish), donde los datos se almacenan en un archivo plano. Para leer/escribir estoy usando la clase RandomAccessFile
. ¿Ganaré algo de multihilo y le daré a cada hilo una instancia cada uno de RandomAccessFile
, o un hilo/instancia será igual de rápido? ¿Hay alguna diferencia en lectura/escritura, ya que puedes hacer instancias que solo hacen la lectura y no pueden escribir?¿Usarás varios subprocesos con un rendimiento de ayuda de RandomAccessFile?
Respuesta
Una pregunta bastante común. Básicamente, el uso de varios subprocesos no hará que su disco duro vaya más rápido. En cambio, realizar una solicitud simultánea puede hacerlo más lento.
Los subsistemas de disco, especialmente IDE, EIDE, SATA, están diseñados para leer/escribir secuencialmente más rápido.
¡Vaya, RandomAccessFile
está sincronizado, por lo que si comparte una instancia, entonces solo tendrá un hilo ejecutándose en uno.
RandomAccessFile
no está sincronizado, y el intercambio entre hilos no es del todo seguro. Como siempre, tendrá que tener cuidado cuando tenga múltiples hilos que accedan a la misma estructura de datos mutable, especialmente cuando se trate de los caprichos de los sistemas operativos.
Las operaciones pequeñas de RandomAccessFile
son terriblemente lentas.
Para obtener el máximo rendimiento, probablemente sea mejor que vaya directamente al java.nio
, aunque sugeriría que funcione algo antes de que funcione rápidamente. OTOH, ten en cuenta el rendimiento.
O nio o incluso nio2 (o el nombre que recibirá ahora) – OscarRyz
Si voy multiproceso, le estoy dando a cada tema su propia instancia. Pero el IO que se hará será el mismo de todos modos, ¿no? Así que pensé que no importaría, y tal vez incluso ralentizaría el sistema: O Además, saber acerca de "haz que funcione primero, luego preocúpate por el rendimiento", acaba de pensarlo;) Gracias de todos modos: D – drRoflol
Oscar: error tipográfico "NIO" y "NIO2" son ambos java.nio. El término NIO.2 fue reemplazado por "Más características de NIO", porque legal quería hacer otra búsqueda para usar NIO.2 y realmente no valía la pena ya que terminará fusionándose. –
Al observar JavaDoc en RandomAccessFile, la clase no está sincronizada. Parece que puede usar un modo síncrono para operaciones de lectura y escritura. Si no usa el modo sincronizado, tendrá que administrar los bloqueos al leer y escribir, lo que no es trivial. Lo mismo va a ser cierto para straight java.io cuando se usan múltiples hilos.
Si es posible, probablemente desee utilizar una base de datos ya que una base de datos proporciona este tipo de abstracción de subprocesos múltiples. También puede ver qué opciones de syslog están disponibles para Java o incluso log4j.
Los bloqueos en las operaciones de lectura/escritura no son un problema, creo que tengo eso cubierto :) – drRoflol
El modo es * sincrónico *, no sincronizado. Esto significa que la llamada al método no volverá hasta que los datos se hayan confirmado en el disco. No proporciona garantías de seguridad de subprocesos, ya que entre una llamada seek() y una llamada read(), otro subproceso podría llamar a seek() a una ubicación diferente. –
Existe una opción para mapear la memoria de su archivo plano con NIO. En ese caso, el administrador de memoria del sistema operativo se vuelve responsable de mover las secciones de entrada del archivo. También puede aplicar bloqueos regionales para escritores.
Según mi experiencia en el desarrollo de C++, la respuesta es: Sí, el uso de varios subprocesos puede mejorar el rendimiento al leer archivos. Esto se aplica tanto al acceso secuencial como al serial. Probé esto más de una vez, aunque siempre encontré que los cuellos de botella reales están en otro lado.
La razón es que para el acceso al disco, un hilo se suspenderá hasta que se complete la operación del disco. Pero la mayoría de los discos actuales son compatibles con Native Command Queuing see (SAS) o Segate (SATA) (al igual que la mayoría de los sistemas RAID) y, por lo tanto, no tienen que manejar las solicitudes en el orden en que las realizas.
Por lo tanto, si lee 4 fragmentos de archivos secuencialmente, su programa tendrá que esperar al primer fragmento, luego solicitará el segundo y así sucesivamente. Si solicita los 4 fragmentos con 4 hilos, se pueden devolver todos a la vez. Este tipo de optimización tiene límites, pero funciona (aunque tengo experiencias solo con C++ aquí). Medí que múltiples hilos pueden mejorar el rendimiento de lectura secuencial en más del 100%.
Ahora hice un punto de referencia con el siguiente código (discúlpeme, está en cpp). El código lee un archivo de texto de 5 MB con un número de subprocesos pasados como un argumento de línea de comando.
Los resultados muestran claramente que múltiples hilos siempre aceleran un programa:
Actualización: Me vino a la mente, ese archivo de almacenamiento en caché jugará un gran papel aquí. Así que hice copias del archivo testdata, reinicié y usé un archivo diferente para cada ejecución. Los resultados actualizados a continuación (los antiguos entre corchetes). La conclusión sigue siendo la misma.
tiempo de ejecución en segundos
máquina A (Dual Xeon Quad Core x64 XP que opera con 4 10k Unidades SAS RAID 5)
- 1 Tema: 0.61s (0.61s)
- 2 Roscas : 0.44s (0.43s)
- 4 Temas: 0.31s (0.28s) (más rápida)
- 8 Temas: 0.53s (0.63s)
Machine B (Laptop Core Dual XP de funcionamiento con un solo fragmentada 2,5 pulgadas Drive)
- 1 Tema: 0.98s (1.01s)
- 2 Temas: 0.67s (0.61s) (más rápido)
- 4 Temas: 1.78s (0.63s)
- 8 Temas: 2.06s (0.80s)
código fuente (Windows):
// FileReadThreads.cpp : Defines the entry point for the console application.
//
#include "Windows.h"
#include "stdio.h"
#include "conio.h"
#include <sys\timeb.h>
#include <io.h>
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int threadCount = 1;
char *fileName = 0;
int fileSize = 0;
double GetSecs(void);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI FileReadThreadEntry(LPVOID lpThreadParameter)
{ char tx[255];
int index = (int)lpThreadParameter;
FILE *file = fopen(fileName, "rt");
int start = (fileSize/threadCount) * index;
int end = (fileSize/threadCount) * (index + 1);
fseek(file, start, SEEK_SET);
printf("THREAD %4d started: Bytes %d-%d\n", GetCurrentThreadId(), start, end);
for(int i = 0;; i++)
{
if(! fgets(tx, sizeof(tx), file))
break;
if(ftell(file) >= end)
break;
}
fclose(file);
printf("THREAD %4d done\n", GetCurrentThreadId());
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
if(argc <= 1)
{
printf("Usage: <InputFile> <threadCount>\n");
exit(-1);
}
if(argc > 2)
threadCount = atoi(argv[2]);
fileName = argv[1];
FILE *file = fopen(fileName, "rt");
if(! file)
{
printf("Unable to open %s\n", argv[1]);
exit(-1);
}
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fclose(file);
printf("Starting to read file %s with %d threads\n", fileName, threadCount);
///////////////////////////////////////////////////////////////////////////
// Start threads
///////////////////////////////////////////////////////////////////////////
double start = GetSecs();
HANDLE mWorkThread[255];
for(int i = 0; i < threadCount; i++)
{
mWorkThread[i] = CreateThread(
NULL,
0,
FileReadThreadEntry,
(LPVOID) i,
0,
NULL);
}
WaitForMultipleObjects(threadCount, mWorkThread, TRUE, INFINITE);
printf("Runtime %.2f Secs\nDone\n", (GetSecs() - start)/1000.);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}
Gracias por compartir esta información. Prefiero los números duros a las manos, especialmente porque este último tiende a convertirse en peleas nerd. –
¡Muchas gracias! Trabajo increíble;) Lo siento, no soy un chico de C++, pero tengo la comprensión de que estás en una máquina de Windows, ¿verdad? – drRoflol
Sí, Windows. ¿Por qué? –
me sorprende cada respuesta habla de rendimiento, pero nadie distingue latencia de rendimiento, mientras que ambos son características de rendimiento. Si bien puede obtener un rendimiento adicional empleando varios hilos, como @RED SOFT ADAIR has shown, puede compensar la latencia, especialmente en el caso de la secuencia de comandos nativos.
- 1. Comprensión de varios subprocesos
- 2. Transacción de Entity Framework con varios subprocesos
- 3. Java: seguro de subproceso RandomAccessFile
- 4. BufferedReader vs RandomAccessFile en Java
- 5. Lectura de un único archivo de varios subprocesos en python
- 6. Identificación única de marca de tiempo de alto rendimiento para varios subprocesos en Haskell
- 7. cómo descargar un solo archivo con varios subprocesos en C#
- 8. Decapado de varios subprocesos en Python
- 9. Consola de llamada.WriteLine de varios subprocesos
- 10. ¿Es posible la carga de clases con varios subprocesos?
- 11. Ejecutar tareas en varios subprocesos en node.js
- 12. ¿Usarás la memoria de limpieza MarshalAs (UnmanagedType.LPWStr)?
- 13. Espere al final de los subprocesos con varios trabajos paralelos
- 14. Java: sincronización de subprocesos en varios servidores
- 15. ¿Es seguro leer de varios subprocesos?
- 16. ¿Cómo un compilador JIT ayuda al rendimiento de las aplicaciones?
- 17. Buffered RandomAccessFile java
- 18. ¿Mejores prácticas para el registro de Java desde varios subprocesos?
- 19. java descarga varios archivos usando subprocesos
- 20. boost :: uuids :: random_generator y unicidad con varios subprocesos
- 21. ¿Realmente Node.js usa varios subprocesos debajo?
- 22. Ayuda para simplificar un Makefile para varios archivos ejecutables
- 23. C# lectura de varios subprocesos de colecciones no modificables
- 24. Ayuda de configuración de Tomcat: varios puertos no responden
- 25. Múltiples subprocesos y rendimiento en una única CPU
- 26. Gestión de sesiones de Spring + Hibernate en varios subprocesos
- 27. ¿Cómo accedo a la GUI (GTK) desde varios subprocesos?
- 28. ¿Cómo esperaría a que se detengan varios subprocesos?
- 29. ¿Cómo se ejecutan varios procesos/subprocesos/interfaces de Tornado?
- 30. Java RandomAccessFile truncado desde el inicio
Gracias, solo la respuesta que quería;) – drRoflol
Si desea un disco duro más rápido, use un disco SSD. Puede ser 5x - 30x más rápido que un disco giratorio, dependiendo de lo que esté haciendo. También usan menos energía. –
Eso no es verdad. La mayoría de los discos son compatibles con la cola de comandos nativos. Ver http: // www.seagate.com/content/pdf/whitepaper/D2c%5Ftech%5Fpaper%5Fintc-stx%5Fsata%5Fncq.pdf –