Domanda

Sto cercando di capire nella mia testa il modo migliore per strutturare un'applicazione Cocoa che è essenzialmente un download manager concorrente. C'è un server i colloqui App per l'utente fa una grande lista di cose da tirare verso il basso, ed i processi di app che elencano. (Non è utilizzando HTTP o FTP, quindi non è possibile utilizzare il sistema di URL-caricamento;. Parlerò attraverso connessioni socket)

Questo è fondamentalmente il classico modello produttore-consumatore. Il trucco è che il numero dei consumatori è fisso, e sono persistenti. Il server imposta un limite rigoroso sul numero di connessioni simultanee che possono essere aperte (anche se di solito almeno due), e l'apertura di nuove connessioni è costoso, quindi in un mondo ideale, gli stessi collegamenti N sono aperte per tutta la durata del app.

Un modo per avvicinarsi a questo potrebbe essere quello di creare N fili, ognuno dei quali avrebbe "possedere" una connessione, e aspettare sulla coda di richieste, bloccando se è vuota. Dal momento che il numero di connessioni non sarà mai grande, questo non è irragionevole in termini di spese generali del sistema. Ma concettualmente, sembra di cacao deve offrire una soluzione più elegante.

Sembra che ho potuto utilizzare un NSOperationQueue , e chiamata setMaxConcurrentOperationCount: con il numero di connessioni. Poi ho solo buttare la richieste di download in quella coda. Ma non sono sicuro, in quel caso, come gestire i collegamenti stessi. (Basta metterli su una pila, e si basano sulla coda per assicurarsi che non over / under-run? Gettare in un spedizione semaforo insieme con lo stack?)

Ora che siamo nel nuovo mondo della Grand Central Dispatch , fa che aprire tutti gli altri modi di affrontare questo? A prima vista, non sembra come esso, dal momento che la capacità di punta di GCD per scalare dinamicamente la concorrenza (e menzionato nelle raccomandazioni di Apple su Modifica produttore-consumatore Implementazioni ) in realtà non mi aiuta. Ma ho appena scalfito la superficie di lettura su di esso.

Modifica

Nel caso in cui è importante: sì, sto pensando di usare i non-bloccanti API asincrone / presa per fare la comunicazione vera e propria con il server. Così l'I / O per sé non deve essere sul proprio thread (s). Sono solo interessati con la meccanica della fila del lavoro, e (in modo sicuro) distribuendo fuori per i collegamenti, non appena saranno disponibili.

È stato utile?

Soluzione 2

Per l'amor di posteri, dopo qualche discussione altrove, la soluzione penso che avrei adotto per questo è fondamentalmente:

  • Avere una coda di attesa di operazioni di download, inizialmente vuota.
  • Avere un insieme contenente tutte le connessioni aperte, inizialmente vuota.
  • dispone di un array mutabile (coda, in realtà) di connessioni aperte inattive, inizialmente vuota.
  • Quando l'utente aggiunge un richiesta di download:
    • Se la matrice di connessioni inattive non è vuoto, rimuovere uno e assegnare il download ad esso.
    • Se non ci sono connessioni inattive, ma il numero di connessioni totali non ha raggiunto il suo limite, aprire una nuova connessione, aggiungerlo al set, e assegnare il download ad esso.
    • In caso contrario, enqueue il download per più tardi.
  • Quando un download completato: le richieste se ci sono in coda, uno dequeue e dare alla connessione; in caso contrario, aggiungere il collegamento alla lista di inattività.

Tutto questo lavoro avrebbe preso posto sul thread principale. Il lavoro di decodificare i risultati di ogni download sarà scaricata su GCD, in modo che possa gestire strozzamento concorrenza, e non intasare il thread principale.

Apertura di una nuova connessione potrebbe richiedere un po ', in modo che il processo di creazione di uno nuovo potrebbe essere un po' più complicata in pratica (per esempio, accodare il download, avviare il processo di connessione, quindi dequeue quando la connessione è completamente stabilito). Ma io continuo a pensare la mia percezione della possibilità di condizioni di gara è stata sopravvalutata.

Altri suggerimenti

Se si utilizza le chiamate non bloccanti di CFSocket per I / O, sono d'accordo, che dovrebbe accadere tutto sul thread principale, lasciando che il sistema operativo di gestire i problemi di concorrenza, dal momento che si sta solo la copia dei dati e non realmente fare alcun calcolo.

Oltre a questo, sembra che l'unico altro lavoro la vostra applicazione ha bisogno di fare è mantenere una coda di elementi da scaricare. Quando uno qualsiasi dei trasferimenti è completa, la parte posteriore chiamata CFSocket può avviare il trasferimento della voce successiva sulla coda. (Se la coda è vuota, diminuire il valore del collegamento, e se si aggiunge qualcosa ad una coda vuota, avviare un nuovo trasferimento.) Non vedo il motivo per cui avete bisogno di più thread per questo.

Forse hai lasciato fuori qualcosa di importante, ma, sulla base di descrizione della app è che O-bound, non CPU / tenuto, per tutte le cose concorrenza è solo andare a rendere il codice più complicato con un impatto minimo sulle prestazioni.

Fare tutto sul thread principale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top