grand dispatchqueue central objective-c c macos optimization grand-central-dispatch

objective c - dispatchqueue - Estrategia Grand Central para abrir múltiples archivos



dispatchqueue swift 4 (5)

Tienes razón en que estarás obligado a E / S, seguramente. Y se verá agravado por la naturaleza de acceso aleatorio de tener múltiples archivos abiertos y ser leídos activamente al mismo tiempo.

Por lo tanto, necesitas equilibrar un poco. Lo más probable es que un archivo no sea el más eficiente, como has observado.

¿Personalmente?

Usaría un semáforo de envío.

Algo como:

@property(nonatomic, assign) dispatch_queue_t dataQueue; @property(nonatomic, assign) dispatch_semaphore_t execSemaphore;

Y:

- (void) process:(NSData *)d { dispatch_async(self.dataQueue, ^{ if (!dispatch_semaphore_wait(self.execSemaphore, DISPATCH_TIME_FOREVER)) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ ... do calcualtion work here on d ... dispatch_async(dispatch_get_main_queue(), ^{ .... update main thread w/new data here .... }); dispatch_semaphore_signal(self.execSemaphore); }); } }); }

Donde se inició con:

self.dataQueue = dispatch_queue_create("com.yourcompany.dataqueue", NULL); self.execSemaphore = dispatch_semaphore_create(3); [self process: ...]; [self process: ...]; [self process: ...]; [self process: ...]; [self process: ...]; .... etc ....

Deberá determinar la mejor forma de manejar la cola. Si hay muchos elementos y existe una noción de cancelación, es muy probable que derrochar todo sea un desperdicio. Del mismo modo, es probable que desee enrutar URL a los archivos para procesar, y no objetos NSData como el anterior.

En cualquier caso, lo anterior procesará tres cosas al mismo tiempo, independientemente de cuántas se hayan puesto en cola.

Tengo una implementación en funcionamiento que utiliza colas de despacho de Grand Central que (1) abre un archivo y calcula un hash OpenSSL DSA en "queue1", (2) escribe el hash en un nuevo archivo "sidecar" para su posterior verificación en "queue2" .

Me gustaría abrir varios archivos al mismo tiempo, pero basados ​​en una lógica que no "estrangula" el sistema operativo al tener cientos de archivos abiertos y que exceden el rendimiento sostenible del disco duro. Las aplicaciones de exploración de fotos como iPhoto o Aperture parecen abrir múltiples archivos y mostrarlos, así que supongo que se puede hacer.

Asumo que la mayor limitación será la E / S de disco, ya que la aplicación puede (en teoría) leer y escribir múltiples archivos simultáneamente.

¿Alguna sugerencia?

TIA


Utilizaría NSOperation para esto debido a la facilidad de manejar tanto las dependencias como la cancelación.

Crearía una operación cada una para leer el archivo de datos, calcular el hash del archivo de datos y escribir el archivo sidecar. Haría que cada operación de escritura dependa de su operación de cómputo asociada, y cada operación de cómputo depende de su operación de lectura asociada.

Luego agregaría las operaciones de lectura y escritura a una NSOperationQueue, la "cola I / O", con un ancho restringido. Las operaciones de cálculo las agregaría a una NSOperationQueue separada, la "cola de cálculo", con un ancho no restringido.

El motivo del ancho restringido en la cola de E / S es que su trabajo probablemente estará vinculado a E / S; es posible que desee que tenga un ancho superior a 1, pero es muy probable que esté directamente relacionado con la cantidad de discos físicos en los que residen sus archivos de entrada. (Probablemente algo así como 2x, querrás determinar esto de manera experimental).

El código terminaría luciendo algo como esto:

@implementation FileProcessor static NSOperationQueue *FileProcessorIOQueue = nil; static NSOperationQueue *FileProcessorComputeQueue = nil; + (void)inititalize { if (self == [FileProcessor class]) { FileProcessorIOQueue = [[NSOperationQueue alloc] init]; [FileProcessorIOQueue setName:@"FileProcessorIOQueue"]; [FileProcessorIOQueue setMaxConcurrentOperationCount:2]; // limit width FileProcessorComputeQueue = [[NSOperationQueue alloc] init]; [FileProcessorComputeQueue setName:@"FileProcessorComputeQueue"]; } } - (void)processFilesAtURLs:(NSArray *)URLs { for (NSURL *URL in URLs) { __block NSData *fileData = nil; // set by readOperation __block NSData *fileHashData = nil; // set by computeOperation // Create operations to do the work for this URL NSBlockOperation *readOperation = [NSBlockOperation blockOperationWithBlock:^{ fileData = CreateDataFromFileAtURL(URL); }]; NSBlockOperation *computeOperation = [NSBlockOperation blockOperationWithBlock:^{ fileHashData = CreateHashFromData(fileData); [fileData release]; // created in readOperation }]; NSBlockOperation *writeOperation = [NSBlockOperation blockOperationWithBlock:^{ WriteHashSidecarForFileAtURL(fileHashData, URL); [fileHashData release]; // created in computeOperation }]; // Set up dependencies between operations [computeOperation addDependency:readOperation]; [writeOperation addDependency:computeOperation]; // Add operations to appropriate queues [FileProcessorIOQueue addOperation:readOperation]; [FileProcessorComputeQueue addOperation:computeOperation]; [FileProcessorIOQueue addOperation:writeOperation]; } } @end

Es bastante sencillo; en lugar de tratar con capas de sincronismo / sincronización sincronizadas de forma múltiple como lo haría con las API dispatch_* , NSOperation le permite definir sus unidades de trabajo y sus dependencias entre ellas de manera independiente. Para algunas situaciones, esto puede ser más fácil de entender y depurar.


Ya has recibido excelentes respuestas, pero quería agregar un par de puntos. He trabajado en proyectos que enumeran todos los archivos en un sistema de archivos y se calculan los hashes MD5 y SHA1 de cada archivo (además de otro procesamiento). Si está haciendo algo similar, donde está buscando una gran cantidad de archivos y los archivos pueden tener contenido arbitrario, entonces algunos puntos a considerar:

  • Como se señaló, estará obligado a E / S. Si lee más de 1 archivo simultáneamente, tendrá un impacto negativo en el rendimiento de cada cálculo. Obviamente, el objetivo de programar cálculos en paralelo es mantener el disco ocupado entre archivos, pero es posible que desee considerar estructurar su trabajo de forma diferente. Por ejemplo, configure un hilo que enumera y abre los archivos y un segundo hilo. El archivo se abre maneja desde el primer hilo uno a la vez y los procesa. El sistema de archivos almacenará en caché la información del catálogo, por lo que la enumeración no tendrá un impacto grave en la lectura de los datos, que en realidad tendrá que golpear el disco.

  • Si los archivos pueden ser arbitrariamente grandes, el enfoque de Chris puede no ser práctico ya que todo el contenido se lee en la memoria.

  • Si no tiene otro uso para los datos que calcular el hash, entonces sugiero que se desactive el almacenamiento en caché del sistema de archivos antes de leer los datos.

Si usa NSFileHandles, un método de categoría simple hará esto por archivo:

@interface NSFileHandle (NSFileHandleCaching) - (BOOL)disableFileSystemCache; @end #include <fcntl.h> @implementation NSFileHandle (NSFileHandleCaching) - (BOOL)disableFileSystemCache { return (fcntl([self fileDescriptor], F_NOCACHE, 1) != -1); } @end

  • Si los archivos del sidecar son pequeños, es posible que desee recopilarlos en la memoria y escribirlos en lotes para minimizar la interrupción del procesamiento.

  • El sistema de archivos (HFS, al menos) almacena registros de archivos para archivos en un directorio secuencialmente, por lo que recorre el sistema de archivos primero (es decir, procesa cada archivo en un directorio antes de ingresar a los subdirectorios).

Lo anterior es solo sugerencias, por supuesto. Querrá experimentar y medir el rendimiento para confirmar el impacto real.


¡libdispatch realmente proporciona API explícitamente para esto! Echa un vistazo a dispatch_io; manejará paralelizar IO cuando sea apropiado, y de lo contrario serializarlo para evitar agitar el disco.


El siguiente enlace es para un proyecto de BitBucket que configuro utilizando NSOperation y Grand Central Dispatch en uso una aplicación primitiva de integridad de archivos.

https://bitbucket.org/torresj/hashar-cocoa

Espero que sea de ayuda / uso.