Question

Je suis en train de travailler dans ma tête la meilleure façon de structurer une application Cocoa qui est essentiellement un gestionnaire de téléchargement simultané. Il y a un serveur les pourparlers app à, l'utilisateur fait une grande liste de choses à tirer vers le bas, et les processus d'application qui liste. (Il ne l'utilise HTTP ou FTP, donc je ne peux pas utiliser le système de chargement d'URL,. Je vais parler à travers les connexions socket)

Ceci est essentiellement le modèle classique producteur-consommateur. L'astuce est que le nombre de consommateurs est fixé, et ils sont persistants. Le serveur fixe une limite stricte du nombre de connexions simultanées qui peuvent être ouvertes (mais le plus souvent au moins deux), et l'ouverture de nouvelles connexions est cher, donc dans un monde idéal, les mêmes connexions N sont ouverts pour la durée de vie de l'application.

Une façon d'aborder ce pourrait être de créer des fils N, dont chacun serait « propre » une connexion, et attendez la file d'attente de la demande, le blocage si elle est vide. Étant donné que le nombre de connexions ne sera jamais énorme, ce n'est pas déraisonnable en termes de frais généraux du système réel. Mais sur le plan conceptuel, il semble que le cacao doit offrir une solution plus élégante.

Il semble que je pourrais utiliser un NSOperationQueue et setMaxConcurrentOperationCount: d'appel avec le nombre de connexions. Ensuite, je viens de lancer les demandes de téléchargement dans cette file d'attente. Mais je ne suis pas sûr, dans ce cas, comment gérer les connexions eux-mêmes. (Il suffit de les mettre sur une pile, et appuyer sur la file d'attente pour assurer que je ne pas sur / sous-terme? Jetez un envoi sémaphore avec la pile?)

Maintenant que nous sommes dans le nouveau monde de Grand Central Dispatch , qui n'ouvrir d'autres moyens de lutter contre cela? À première vue, il ne semble pas, puisque la capacité phare de GCD à l'échelle dynamique concurrency (et mentionné dans les recommandations d'Apple sur Changement Implémentations producteur-consommateur ) ne me permet pas réellement. Mais je viens gratté la surface de lecture à ce sujet.

EDIT:

Dans le cas où il importe: oui, je prévois sur l'utilisation des asynchrones / API socket non bloquant pour faire la communication réelle avec le serveur. Ainsi, le E / S lui-même n'a pas à être sur son propre fil (s). Je suis préoccupé par la mécanique de faire la queue du travail et (en toute sécurité) doling dehors aux connexions, qu'ils deviennent disponibles.

Était-ce utile?

La solution 2

Pour l'amour de la postérité, après une discussion ailleurs, la solution que je pense que j'adopte pour cela est essentiellement:

  • Avoir une file d'attente d'opérations en attente de téléchargement, initialement vide.
  • Avoir un ensemble contenant toutes les connexions ouvertes, initialement vide.
  • Avoir un tableau mutable (file d'attente, vraiment) de connexions ouvertes au repos, initialement vide.
  • Lorsque l'utilisateur ajoute une demande de téléchargement:
    • Si le tableau de connexions inactives n'est pas vide, enlever une et affecter le téléchargement à elle.
    • S'il n'y a pas des connexions inactives, mais le nombre total de connexions n'a pas atteint sa limite, ouvrez une nouvelle connexion, ajoutez à l'ensemble, et attribuer le téléchargement à elle.
    • Dans le cas contraire, le téléchargement file d'attente le plus tard.
  • Quand un téléchargement terminé: s'il y a des demandes en file d'attente, un dequeue et donner à la connexion; sinon, ajoutez la connexion à la liste de veille.

Tout ce travail aurait lieu sur le thread principal. Le travail de décodage des résultats de chaque téléchargement serait débarquée à GCD, il peut gérer étranglant le concurrency, et il ne se bouche pas le fil principal.

L'ouverture d'une nouvelle connexion peut prendre un certain temps, de sorte que le processus de création d'une nouvelle pourrait être un peu plus compliqué dans la pratique (par exemple, enqueue le téléchargement, lancer le processus de connexion, puis dequeue quand la connexion est entièrement établi). Mais je pense toujours que ma perception de la possibilité de conditions de course a été surestimée.

Autres conseils

Si vous utilisez les appels non-blocage de CFSocket pour E / S, je suis d'accord, cela devrait tout arriver sur le thread principal, laissant le système d'exploitation gérer les problèmes de concurrence, étant donné que vous copiez simplement les données et ne pas faire vraiment de calcul.

Au-delà, il semble que le seul autre travail que votre application doit faire est de maintenir une file d'attente d'éléments à télécharger. Quand l'un des transferts est terminée, le retour d'appel CFSocket peut initier le transfert de l'élément suivant de la file d'attente. (Si la file d'attente est vide, votre décrémenter compte de connexion, et si quelque chose est ajouté à une file d'attente vide, démarrer un nouveau transfert.) Je ne vois pas pourquoi vous avez besoin de plusieurs threads pour cela.

Peut-être que vous avez omis quelque chose d'important, mais en fonction de votre description, l'application est E / S lié, non lié CPU, de sorte que tous les trucs de la concurrence va tout simplement rendre le code plus compliqué avec un impact minimal sur les performances.

Faites-le tout sur le thread principal.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top