Questions sur l'hyperthreading...

Bonjour à  tous !


 


Je crois avoir compris, que pour utiliser le second thread des iPhones, il faut utiliser DispatchQueue.global(qos: .userInteractive).async ou une closure. Si j'ai bien compris, une closure est une fonction sans nom, que l'on appelle à  l'intérieur d'une autre fonction, par le biais d'un completion block, et qui permet d'utiliser le second thread.


 


Dites-moi si je me trompe.


 


 


Lorsque l'on utilise DispatchQueue.global(qos: .userInteractive).async, est-il mieux de l'utiliser dans la déclaration d'une fonction, ou à  l'appelle de ladite fonction ?


 


Je sais aussi, que les nouveaux iPhone 8, 8 plus et l'iphone X, sont équipé d'un CPU ou SoC à  6 thread. Mais je suppose que l'on ne peut pas profiter pleinement de tous ces thread, et qu'il faut attendre l'accord d'Apple avant de pouvoir les exploiter. Est-ce correct ?


 


Je vous remercie pour vos réponses !


Réponses

  • Non, 


    tu peux automatiquement utiliser tous les coe“urs.


    En pratique, ce n'est pas toi qui décide combien de coe“urs vont être utilisés. C'est le système qui automatiquement dispatche les différents threads sur les différents coe“urs.


     


    Colas


  • CéroceCéroce Membre, Modérateur
    octobre 2017 modifié #3

    Dites-moi si je me trompe.

     
    Tu te trompes  >:D
     

    Je crois avoir compris, que pour utiliser le second thread des iPhones,

    Alors déjà  attention. Un thread est une unité d'exécution au sein d'un même processus. Même si le CPU n'a qu'un seul coe“ur, on peut très bien avoir plusieurs threads, qui s'exécutent en "parallèle" " du moins du point de vue de l'utilisateur.
     

    il faut utiliser DispatchQueue.global(qos: .userInteractive).async

    Ce n'est qu'un moyen parmi d'autres. On a aussi NSThread (à  déconseiller) mais aussi NSOperationQueue. Certaines classes créent aussi des threads sans intervention de notre part. Un bon exemple étant NSURLSession.
     

    ou une closure. Si j'ai bien compris, une closure est une fonction sans nom,

    Une closure est une fonction qui "capture" son environnement.
    Nous en parlions là : http://forum.cocoacafe.fr/topic/15421-closures-définition-utilité/

    Pour être tout à  fait clair, une closure peut s'exécuter sur n'importe quel thread, même sur un thread différent de celui qui l'a créée.
     

    que l'on appelle à  l'intérieur d'une autre fonction,

    comme toute les fonctions...
     

    par le biais d'un completion block, et qui permet d'utiliser le second thread.

    Non. Un "completion block" est une closure qui est appelée quand une opération se termine.
    Par exemple, la méthode

    UIViewController.present(_ controller: UIViewController, animated: Bool, completion: (() -> Void)?)

    présente un autre View Controller à  l'écran. La closure de complétion est appelée quand l'animation d'affichage se termine, sur le thread principal.
     

    Lorsque l'on utilise DispatchQueue.global(qos: .userInteractive).async, est-il mieux de l'utiliser dans la déclaration d'une fonction, ou à  l'appelle de ladite fonction ?

    ça dépend. Je dirais que c'est une question de conception: ton but est que l'API soit la plus simple à  utiliser possible. Pour reprendre l'exemple de NSURLSession, elle crée les threads de façon transparente parce que les requêtes réseau mettent toujours du temps à  répondre. Autrement, ce serait à  nous de créer un thread secondaire à  chaque fois, ce qui n'est pas pratique.
     

    Je sais aussi, que les nouveaux iPhone 8, 8 plus et l'iphone X, sont équipé d'un CPU ou SoC à  6 thread. Mais je suppose que l'on ne peut pas profiter pleinement de tous ces thread, et qu'il faut attendre l'accord d'Apple avant de pouvoir les exploiter. Est-ce correct ?

    Non, c'est totalement faux. Quand on utilise Grand Central Dispatch (DispatchQueue) ou NSOperation, c'est le système d'exploitation qui répartit les threads sur les différents coe“urs.
    À partir du moment où les coe“urs existents, il seront exploités. À la charge du programmeur d'essayer de libérer le thread principal en répartissant le travail dans d'autres threads pour exploiter au mieux cette puissance.
  • J'arrive après la bataille ! Comme mes collègues l'ont dis, tu n'as pas a te préoccuper de l'utilisation des threads physiques des processeurs. Si tu lances le moniteur d'activité sous macOS, tu peux voir que des dizaines de processus (voire plus) tournent en temps réel sous le capot. C'est la même chose pour iOS. Le système d'exploitation se charge d'attribuer les processus logiques aux ressources systèmes disponibles. C'est transparent pour le développeur, que ce soit sur un processeur mono-coeur ou un bidule de dernière génération  comme l'A11 Bionic multi-core de la mort-qui-tue-encore-mieux-que-la-mort des iPhone 8 et X.

  • Luc-ALuc-A Membre
    octobre 2017 modifié #5

    Je vous remercie beaucoup pour vos réponses ! C'est plus clair dans mon esprit !


     


    Donc, c'est plus facile de programmer en Swift que dans un langage où c'est le développeur qui décide du nombre de coe“ur, comme en C. Je ne connais pas du tout le C, alors je dis peut-être une bêtise...


     


    Je me suis mal exprimé. Un coe“ur est physique, et un thread est virtuel. Enfin, ça c'est pour les processeurs Intel et AMD (entre autres), mais je pense que c'est un peu plus complexe.


     


    Céroce, je vais reprendre un autre exemple, car il y a quelque chose que je ne saisi pas...


    Lorsque l'on récupérer les données d'une API, on utilise une closure. On enregistre les données que l'on reçoit dans une variable, et on met à  jour la vue (souvent tableView.reloadData(). Mais dans ce cas, je suppose que la closure est exécutée sur un autre thread, car il faut utiliser DispatchQueue.main.async pour recharger la vue.


     


    Et il y a quelque chose que je ne comprend pas : pourquoi utiliser un completion block, pour récupérer les données d'une API lorsque le chargement de la page est finie ? Ne vaut-il pas mieux utiliser l'hyperthreading, et donc, se servir d'autre(s) thread(s) que du thread principal pour charger les données en même temps que le chargement de la page, afin de gagner du temps ?


    Et plus généralement, comment faire pour exécuter deux fonctions en même temps ?


    J'ai bien compris que si l'on veut exécuter une fonction après l'autre, il faut utiliser un completion block, ou peut-être defer selon les cas. Dites-mois si je me trompe.


     


    Pour mon application, j'ai utilisé DispatchQueue pour effectuer les modifications de la base de données (suppression ou mise à  jour). Je l'ai utilisé dans la déclaration des fonctions, car c'est plus pratique à  l'appel de la fonction, et plus logique.


     


    Effectivement, j'ai bien compris, je n'ai pas à  m'occuper des threads. J'ai juste à  faire en sorte que mes applications ne soit pas trop longues à  charger.


     


    Merci !


  • LeChatNoirLeChatNoir Membre, Modérateur

    Ben en fait, les completion block, c'est utilisé uand une méthode balance une tâche asynchrone justement.


    Donc la main thread continue sont chemin et quand la méthode asynchrone répond, le completion block se déclenche.


  • CéroceCéroce Membre, Modérateur
    octobre 2017 modifié #7

    Lorsque l'on récupérer les données d'une API, on utilise une closure.

    Je pense que tu veux dire implicitement une "API fournie par un serveur web". Dans ce cas effectivement, on passe une closure en paramètre, qui sera appelée quand le serveur aura répondu.
     

    On enregistre les données que l'on reçoit dans une variable, et on met à  jour la vue (souvent tableView.reloadData(). Mais dans ce cas, je suppose que la closure est exécutée sur un autre thread, car il faut utiliser DispatchQueue.main.async pour recharger la vue.

    Oui. Il y a une chose importante à  savoir sur iOS: tout ce qui concerne l'interface homme machine (IHM) doit s'exécuter sur le thread dit " principal ", celui qui correspond à  la fonction main() du programme. D'ailleurs Xcode 9 vérifie que tu n'appelles de méthodes de classes commençant par "UI" depuis un thread secondaire.

    Quand on fait une requête réseau, on ne la lance pas sur le thread principal, parce que le serveur web peut mettre plusieurs secondes à  répondre, pendant lesquelles le thread va attendre, donc bloquer l'IHM!
    C'est pour cela que les classes qui gèrent les appels HTTP (NSURLConnection et NSURLSession) créent des threads secondaires automatiquement.
    Quand NSURLSession a fini, elle appelle la closure de complétion sur son thread secondaire. Comme on ne doit pas appeler de fonction de l'IHM sur un thread secondaire, la closure de complétion doit utiliser DispatchQueue.main.async() pour raffraichir l'IHM.
     

    Et il y a quelque chose que je ne comprend pas : pourquoi utiliser un completion block, pour récupérer les données d'une API lorsque le chargement de la page est finie ? Ne vaut-il pas mieux utiliser l'hyperthreading, et donc, se servir d'autre(s) thread(s) que du thread principal pour charger les données en même temps que le chargement de la page, afin de gagner du temps ?

    Je ne comprends pas bien la question, mais j'y ai sûrement répondu.
     

    Et plus généralement, comment faire pour exécuter deux fonctions en même temps ?

    Dans GCD (Grand Central Dispatch, les fonctions qui commencent par Dispatch), il y a deux types de queues: "série" et "parallèle". Dans une queue série, les opérations s'exécutent les unes à  la suite des autres. Dans une queue parallèle, en même temps.
    Par défaut, les queues sont parallèles; la queue principale (celle qui correspond au thread principal) est une queue série.
    Je ne peux pas aller dans les détails ici, mais il y a des vidéos de la WWDC qui en parlent.
    (NS)OperationQueue apporte une couche objet qui peut être pratique. Par exemple, mettre maxConcurrentOperationCount à  1 rend la queue sérielle.
     

    J'ai bien compris que si l'on veut exécuter une fonction après l'autre, il faut utiliser un completion block, ou peut-être defer selon les cas. Dites-mois si je me trompe.

    Le problème est que tu peux ainsi te retrouver avec des blocs de complétion en cascade. (Il y a des solutions).
    Et tu peux aussi utiliser une queue série.
     

    Pour mon application, j'ai utilisé DispatchQueue pour effectuer les modifications de la base de données (suppression ou mise à  jour). Je l'ai utilisé dans la déclaration des fonctions, car c'est plus pratique à  l'appel de la fonction, et plus logique.

    Utiliser un thread secondaire permet surtout de libérer le thread principal et d'améliorer la fluidité de l'IHM. Le tout est de faire attention aux accès concurrents. Comme SQLite ne permet de toute façon pas les accès concurrents, utiliser une queue série semble la meilleure pratique.
  • DrakenDraken Membre
    octobre 2017 modifié #8


     


    Et il y a quelque chose que je ne comprend pas : pourquoi utiliser un completion block, pour récupérer les données d'une API lorsque le chargement de la page est finie ? Ne vaut-il pas mieux utiliser l'hyperthreading, et donc, se servir d'autre(s) thread(s) que du thread principal pour charger les données en même temps que le chargement de la page, afin de gagner du temps ?


     




     


    Comme le souligne le félidé et le rhino, le chargement d'une page à  partir d'une source externe (Web, API, parseur XML, et..) est asynchrone. On sait quand ça commence, pas quand cela vas finir (2 secondes, 17,2 secondes, une minute, etc..). Le bloc de complétion permet de prévenir l'application que " OK, c'est bon les données sont chargées ".


     


    Et l'hyerperthreading est deja utilisé, de manière transparente par l'OS, lors de la création du processus asynchrone.


Connectez-vous ou Inscrivez-vous pour répondre.