Question

J'ai une application qui tire des données sur le web, les analyse, et compile les résultats dans une interface de recherche. Étant donné que les données ne sont pas co-dépendants, il était logique de multi-thread l'application à exécuter plusieurs récupérations et parse simultanément. J'utilise NSInvocationOperation sur une recherche et parse objet que je l'ai écrit pour exécuter cette fonction.

Dans l'objet de contrôleur je le procédé suivant:

-(void) searchAndParseAsynchronously { 
 NSPort *serverPort = [NSMachPort port];
 NSConnection *serverConnection = [NSConnection connectionWithReceivePort:serverPort sendPort:serverPort];
 [serverConnection setRootObject:self];
 for (NSURL *urlToProcess in self.urlsToFetch)
 {
  BaseSearchParser *searcherForURL = [BaseSearchParser newSearchParserWithParameters:self.searchParams];
  searcherForURL.urlToDocument = urlToDocument;

  SearchThreader *searchThreader = [SearchThreader new];
  searchThreader.threadConnection = comConnection;
  searchThreader.targetSchema = searcherForURL; 
  NSInvocationOperation *threaderOperation = [[NSInvocationOperation alloc] initWithTarget:searchThreader 
                                                                                        selector:@selector(executeSearchParse) 
                                                                                          object:nil];
  [self.operationQueue addOperation:threaderOperation];
 }
}

L'application repose sur des données de base, que j'ai rassemblé est la plupart du temps du fil dangereux. J'ai un autre NSManagedObjectContext pour chaque opération de recherche / d'analyse syntaxique (et une pour l'unité de commande), et ne passe la NSManagedObjectId entre des opérations ou des objets proxy.

Les opérations communiquent les résultats parse terminés à leur contrôleur via un objet NSConnection. Le contrôleur construit le NSConnection en utilisant un objet NSMachPort, se définit comme l'objet racine, et donne le même objet NSConnection à chacune des cibles des NSInvocationOperations. Le contrôleur enqueues alors le NSInvocationOperation pour l'exécution dans son propre NSOperationQueue.

Dans l'objet enfileur de recherche J'ai la méthode suivante:

-(void) executeSearchAndParse
{ 
 id parentServer = [threadConnection rootProxy];
 [parentServer setProtocolForProxy:@protocol(SearchParseProtocol)];

 NSArray *importResults = [targetSchema generatedDataSetIds];

 [parentServer schemaFinished:targetSchema];
 [parentServer addSearchResults:importResults];
}

Je crois que je l'ai suivi l'exemple d'Apple de communication inter-thread générique donné ici .

Je dois dire que la plupart du temps, cela fonctionne à merveille: Les notifications de la rootProxy NSConnection sont affichés à la boucle d'exécution dans le thread principal comme prévu et attendre jusqu'à ce que le pick-up objet contrôleur est prêt. Cependant, il provoque dans certains de mes cas de test de base de données à moudre à un arrêt brutal parce que parfois les messages qu'il font l'objet de commande dans le même thread que l'objet NSInvocationOperation qui appelle l'objet rootProxy .

J'ai placé un point de débogage dans le contrôleur sur le message qui est envoyé lorsque la recherche / parser opération est terminée, et bien sûr, parfois (juste parfois) le fil d'exécution est pas la principal. Est-ce que quelqu'un a une idée de pourquoi cela pourrait se produire? Ou, est-il un moyen plus simple de construire une communication asynchrone inter-thread? OU est mon approche pour Core Data totalement hors bon état de marche?

Merci d'avance!

Était-ce utile?

La solution

Je ne vois rien de mal avec votre approche et ont utilisé NSConnection de manière similaire avant. La seule chose que je vois que j'est que je viens d'utiliser NSPort au lieu d'utiliser NSMachPort explicitement.

  

Ou, est-il un moyen plus simple de construire une communication asynchrone inter-thread?

Je ne pense pas que Apple fait la promotion des objets ditributed pour la communication inter-thread plus. IIRC cette estimation est principalement basée sur la documentation que je l'ai vu mentionné ce qui favorise vraiment pour la communication entre DOs fils mais qui depuis ont été supprimés ou modifiés.

Je pense aussi que le performSelector liés aux threads: méthodes sur NSObject sont beaucoup plus faciles à utiliser:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait

(tandis que le second est disponible à partir de 10,5 de suite).

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