filteredArrayUsingPredicate: sur le main thread avec réception du resultat

FloFlo Membre
18:13 modifié dans API AppKit #1
Bonjour à  tous,

quelqu'un aurait-il une solution élégante pour résoudre ce problème :

<br />result = [_tradeSites performSelectorOnMainThread: @selector(filteredArrayUsingPredicate:) withObject: predicate waitUntilDone: YES];<br />


de mon côté je vois plusieurs solutions qui ne me plaisent pas vraiment :
- une catégorie sur NSArray, du genre filteredArrayUsingPredicate: (NSPredicate *)predicate results: (NSArray **)results
- exécuter le filtrage dans une méthode plus générale lancée sur le main thread

merci d'avance pour votre (précieuse) aide  :D

Réponses

  • AliGatorAliGator Membre, Modérateur
    18:13 modifié #2
    C'est quoi l'intérêt d'utiliser performSelectorOnMainThread à  cet endroit ?
  • FloFlo Membre
    18:13 modifié #3

    C'est quoi l'intérêt d'utiliser performSelectorOnMainThread à  cet endroit ?


    A l'origine la recherche est lancée par un thread concurrent.

    Le tableau à  filtrer contient des objets qui peuvent être modifiés par le main thread. J'ai pensé que comme mon NSPredicate interrogeait ces objets, il était nécessaire de lancer la recherche également sur le main thread pour éviter les accès concurrents... me trompe-je ?  :D
  • AliGatorAliGator Membre, Modérateur
    18:13 modifié #4
    Bah tu peux mais comme de toute façon ton tableau est apparemment modifié par ton thread secondaire... Tu peux faire le tri dans le thread secondaire, et une fois le tri fait demander au thread principal de mettre à  jour son ancien tableau avec le nouveau tableau trié. Cette mise à  jour devra se faire de façon atomique (avec des @synchronized ou plus simplement avec des @property qui si elle ne sont pas "nonatomic" font ça bien).
  • FloFlo Membre
    18:13 modifié #5
    Oui c'est pas faux, merci pour ta réponse... le truc c'est que le NSPredicate du filtrage accède à  des variables des objets du tableau qui peuvent être modifiées en même temps par le thread principal.

    Mais je me pose deux petites questions :
    • qu'est-ce qui est le plus coûteux, utiliser des @synchronized/properties atomic ou alors exécuter le code conflictuel dans le thread principal avec performSelectorOnMainThread ?
    • y à  t-il des risques de conflits si deux threads exécutent en même temps une méthode qui ne fait qu'accèder à  un objet partagé ?


  • FloFlo Membre
    18:13 modifié #6
    J'ai la réponse pour la question 2 mais en ce qui concerne la 1 ??

    Pas d'idées ??  :(
  • AliGatorAliGator Membre, Modérateur
    janvier 2010 modifié #7
    Mince je pensais avoir répondu ?!

    Alors :
    1) performSelectorOnMainThread n'exécute pas directement la méthode. Il empile l'appel de la méthode dans une pile de la RunLoop dédiée à  ça, qui empile donc les appels en attente. Ensuite, quand la RunLoop boucle, au début de chaque cycle, elle dépile ces appels mis en attente et les exécute.
    C'est exactement comme les NSTimers, qui sont "schedulés" sur la RunLoop donc mis dans une pile, et à  chaque boucle de la RunLoop le système vérifie tous les timers "schedulés" et regarde s'il y en a à  déclencher (si leur date a expiré). Bah là  c'est pareil.

    Alors que @synchronized (ou l'utilisation des @property atomic) placent un mutex, donc bloquent le thread appelant si le mutex est déjà  pris, mais au moins ensuite ne chamboulent pas l'ordre d'exécution des méthodes.

    Autrement dit si tu as un truc asynchrone à  faire, genre "bon quand t'auras le temps, enfin quand le thread principal aura la main et fera un tour de runloop, exécute ce selector sur le thread principal), ce qui est typiquement le cas pour une mise à  jour de l'interface, alors utilise performSelectorOnMainThread.
    Si tu veux faire des accès concurrents ordonnancés (entre autres s'ils sont synchrones et que tu attends une réponse de leur part, mais pas que), utilise @synchronized. Ce sont deux usages bien distincts dans leur buts et motivations en tout cas.

    Mais normalement si tu mets bien tes @synchronized sur uniquement la ressource (variable, ...) à  protéger contre les accès concurrentiels, et pas sur un super gros bloc (genre si tu as une boucle for qui dans chaque itération accède à  une variable, mettre le @synchronize à  l'intérieur de la boucle "for" et non à  l'exétieur permet aux autres threads d'accéder à  cette variable entre les cycles de la boucle "for" au lieu de bloquer son accès pendant toute la boucle), pour ce genre de cas où tu ne fais pas des accès massifs avec des calculs intensifs, ça va pas bloquer bien longtemps, voire ça va pas bloquer du tout sauf dans de rares cas où les accès sont concurrentiels mais du coup ça va éviter les crash.



    Pour la question 2, oui il y a des risques de conflits même avec uniquement de la lecture. C'est moins trivial et visible à  voir, après tout c'est pas comme le risque qu'on écrive une variable pendant qu'on est aussi en train de la lire, mais bon, c'est jamais trop prudent de tout façon même si ce n'est que de la lecture, je conseillerai quand même de mettre des @synchronized.

    De toute façon ne t'inquiètes pas, si t'as pas un algo de folie avec des mutex dans tous les sens risquant des deadlocks, et si tu fais les choses propres, les @synchronized ne vont pas ralentir ton code. Enfin si, bien sûr, loe positionnement des mutex va prendre quelques microsecondes, et si tu as un accès concurrent ça va être bloquant quelques millisecondes (mais ça va éviter que ça crash), à  la limite... mais bon, c'est pas ça qui devrait faire laguer ton appli je veux dire. Tant que c'est pas du calcul intensif où la moindre microseconde gagnée est importante, te prend pas la tête et privilégie la protection de tes ressources par mutex ou @synchronized à  l'optimisation des temps d'accès au risque de crasher si accès concurrents, quoi.
  • FloFlo Membre
    18:13 modifié #8

    Mince je pensais avoir répondu ?!


    Héhé, je savais bien que tu ne m'avais pas abandonné ! 
    Merci pour cette réponse constructive et pertinente ! C'est exactement ce que je voulais savoir !  :D
Connectez-vous ou Inscrivez-vous pour répondre.