Pregunta

Estoy tratando de hacer ejercicio en mi cabeza la mejor manera de estructurar una aplicación de cacao que es esencialmente un gestor de descargas concurrentes. Hay un servidor de aplicaciones para las conversaciones a, el usuario hace una gran lista de cosas para tirar hacia abajo, y los procesos de aplicación de esa lista. (No está utilizando HTTP o FTP, por lo que no puede utilizar el sistema de dirección URL de carga;. Voy a estar hablando a través de conexiones de socket)

Este es básicamente el patrón clásico del productor-consumidor. El truco es que el número de consumidores es fija, y son persistentes. El servidor establece un límite estricto en el número de conexiones simultáneas que se pueden abrir (aunque por lo general al menos dos), y la apertura de nuevas conexiones es caro, por lo que en un mundo ideal, las mismas conexiones N están abiertos para el tiempo de vida de la aplicación.

Una manera de abordar esto podría ser la creación de N hilos, cada uno de los cuales sería el "titular" de una conexión, y esperar en la cola de solicitudes, el bloqueo si está vacío. Dado que el número de conexiones nunca será enorme, esto no es razonable en términos de sobrecarga del sistema real. Sin embargo, conceptualmente, parece cacao debe ofrecer una solución más elegante.

Parece como si pudiera utilizar un NSOperationQueue y setMaxConcurrentOperationCount: llamada con el número de conexiones. Entonces se deshacen de las solicitudes de descarga en esa cola. Pero no estoy seguro, en ese caso, cómo manejar las propias conexiones. (Sólo ponerlos en una pila, y se basan en la cola para asegurarse de que no sobre / contra agotamiento? Tiro en un despacho semáforo junto con la pila?)

Ahora que estamos en el nuevo mundo de la de Grand Central Dispatch , no que se abren otras maneras de hacer frente a esto? A primera vista, no parece como que, ya que la capacidad del buque insignia de GCD para escalar dinámicamente concurrencia (y menciona en las recomendaciones de Apple en Cambio de productor-consumidor Implementaciones ) en realidad no me ayuda. Pero acabo de arañado la superficie de leer sobre él.

EDIT:

En caso de que importa: sí, estoy planeando sobre el uso de las API asíncronas / no-bloqueo de socket para hacer la comunicación real con el servidor. Por lo que la E / S en sí no tiene que estar en su propio hilo (s). Estoy preocupado por la mecánica de la cola de la obra, y (con seguridad) que repartir a las conexiones, a medida que estén disponibles.

¿Fue útil?

Solución 2

Por el bien de la posteridad, después de un rato otra parte, la solución creo que me adopten para esto es básicamente:

  • Tener una cola de espera de las operaciones de descarga, inicialmente vacío.
  • Disponer de un conjunto que contiene todas las conexiones abiertas, inicialmente vacío.
  • Tener una matriz mutable (cola, en realidad) de conexiones abiertas ociosos, inicialmente vacío.
  • Cuando el usuario agrega una solicitud de descarga:
    • Si la matriz de conexiones inactivas no está vacío, quite uno y asignar la descarga a la misma.
    • Si no hay conexiones inactivas, pero el número total de conexiones no ha llegado a su límite, abrir una nueva conexión, añadirlo al conjunto, y asignar la descarga a la misma.
    • Si no, encolar la descarga para más adelante.
  • Cuando una descarga completa: si hay solicitudes están en la cola, uno dequeue y darle a la conexión; de lo contrario, agregue la conexión a la lista inactiva.

Todo ese trabajo se llevaría a cabo en el hilo principal. El trabajo de decodificar los resultados de cada descarga se descarga en GCD, por lo que puede manejar estrangular la concurrencia, y no obstruye el hilo principal.

La apertura de una nueva conexión podría tomar un tiempo, por lo que el proceso de creación de uno nuevo podría ser un poco más complicado en la práctica real (por ejemplo, poner en cola la descarga, iniciar el proceso de conexión y, a continuación, quitar de la cola cuando la conexión es totalmente establecido). Pero sigo pensando que mi percepción de la posibilidad de condiciones de carrera fue exagerada.

Otros consejos

Si está utilizando llamadas no bloqueantes de CFSocket para E / S, estoy de acuerdo, que todos deben pasar en el hilo principal, dejando que el sistema operativo manejar los problemas de concurrencia, ya que sólo está copiando los datos y no realmente hacer cualquier cálculo.

Más allá de eso, parece que el único otro trabajo que su aplicación tiene que hacer es mantener una cola de elementos para ser descargado. Cuando cualquiera de las transferencias es completa, la parte posterior llamada CFSocket puede iniciar la transferencia del siguiente elemento de la cola. (Si la cola está vacía, disminuir el número de conexiones, y si algo se añade a una cola vacía, iniciar una nueva transferencia.) No veo por qué necesita múltiples hilos para eso.

Tal vez usted ha dejado fuera algo importante, pero en base a la descripción de la aplicación es de E / S de la envolvente, no CPU obligado, por lo que toda la materia de concurrencia es sólo va a hacer el código más complicado con un impacto mínimo en el rendimiento.

Hacerlo todo en el hilo principal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top