Puis-je utiliser les 4 cœurs du processeur du Raspberry Pi?

11

Je me demandais s'il y avait un moyen simple de "mettre sous tension" tous les 100% du CPU afin que je puisse exécuter des processus plus rapidement (comme les calculs python).

1) Est-ce possible?

2) Existe-t-il un moyen facile de revenir à la normale?

3) Existe-t-il un moyen d'utiliser moins de CPU si vous le souhaitez?

Je pense à une interaction en ligne de commande comme:

pi@raspberry:~ $ sudo turnOnFourCores python run.py

NaN
la source
1
La réponse courte est non
Steve Robillard
16
La réponse longue est "Si c'était aussi simple que ça, ce serait la valeur par défaut"
Shadow
18
Vos deux commentaires sont trompeurs et pourraient impliquer que le Pi a 4 cœurs mais n'en utilise que 1. Une meilleure réponse est que les quatre cœurs SONT déjà allumés , mais que Python (et tout autre programme, d'ailleurs) n'en utilisera plus de 1 cœur, sauf s'ils sont multi-thread. Python peut toujours être bloqué en utilisant un seul cœur, même avec plusieurs threads en raison du verrouillage de l'interpréteur global, mais cela dépasse un peu la portée de cette question.
Sohcahtoa82
13
Pour clarifier, je pense que l'OP a un malentendu sur le fonctionnement des processeurs multicœurs, et vos réponses ne font que renforcer leur malentendu.
Sohcahtoa82
6
La façon la plus simple de rendre un programme Python plus rapide est de réécrire dans un langage compilé (ou au moins de faire en sorte que les tâches critiques en temps utilisent un module ca).
Milliways

Réponses:

21

Par défaut, tout ordinateur essaiera d'utiliser tous ses cœurs quand il le pourra. Cependant, il ne peut y parvenir que lorsqu'une application est multithread. Si ce n'est pas le cas (c'est-à-dire un script Python qui n'utilise pas le threadingmodule), alors il ne peut utiliser au maximum qu'un seul cœur. Cela équivaut à 25% du processeur sur un processeur à quatre cœurs. Si vous souhaitez modifier votre script pour utiliser plusieurs cœurs, vous pouvez diviser votre calcul en plusieurs parties et le multi-thread comme indiqué dans la documentation Python .

Mise à jour:

Comme Anon a répondu , cela ne fonctionnera pas sans travailler avec GIL (Global Interpreter Lock) de Python. Cela permet aux tâches de fonctionner (apparemment) en même temps, mais ne permet pas au code de s'exécuter sur plusieurs cœurs. Si vous utilisez des modules écrits en C (par exemple numpy), ils peuvent vous permettre d'utiliser plusieurs cœurs pour contourner cette limitation. De plus, si ce n'est pas une option, Python propose un multitraitement , qui vous permet d'exécuter n'importe quelle tâche sur plusieurs cœurs.

lights0123
la source
La mise à jour - qui est correcte - explique pourquoi la première partie de la réponse est erronée en ce qui concerne Python. Vous ne contournez cette limitation de Python qu'en écrivant des modules C ou un langage compilé, auquel cas vous n'écrivez plus vraiment du tout en Python. Si les performances sont critiques, passer à un langage compilé est la bonne réponse. (Le multitraitement n'est pas le même du point de vue de l'utilisation des ressources.)
Brick
4
@Brick Pour être clair, un langage compilé n'est certainement pas une exigence pour un multithreading en cours de processus. Heck, même le GIL de Python est un détail d'implémentation (accordé, pour le CPython populaire) - il existe d'autres interprètes Python qui seront volontiers multithread, par exemple Jython et IronPython.
Bob
4
Ajoutant à la confusion, Python est compilé; dans le cas de CPython, il se compile en bytecode CPython qui est exécuté dans la machine virtuelle CPython. Pour Jython, il est compilé en bytecode Java qui est exécuté dans la JVM. Enfin, IronPython se compile en CIL, qui cible le runtime .NET. Donc, "aller dans un langage compilé" pour la performance n'a pas vraiment de sens;)
marcelm
n'importe quel ordinateur essaiera d'utiliser tous ses cœurs quand il le pourra. Pas vraiment, il n'utilisera tous ses cœurs (ou ne fera rien d'autre) lorsque cela lui sera demandé . Cette distinction peut sembler évidente, voire condescendante, à l'expérimenté, mais il semble que le PO doive comprendre qu'il ne se produit pas automatiquement.
nekomatic
13

Je me demandais s'il y avait un moyen simple de "mettre sous tension" tous les 100% du CPU afin que je puisse exécuter des processus plus rapidement (comme les calculs python).

Pas dans le sens que je pense que vous sous-entendez. Ce n'est pas non plus un problème spécifique au pi, c'est une contrainte logique.

À eux seuls, les ordinateurs n'ont actuellement pas beaucoup de capacité pour déterminer qu'un processus s'exécutant en tant que thread unique peut à la place être exécuté en parallèle. Notez qu'au moment où ils pourraient avoir cette capacité, il n'y aurait pas besoin de programmeurs informatiques, car un système informatique qui pourrait le faire pourrait aussi bien écrire son propre code 1 ..

Considérez l'expression mathématique simple suivante:

(4 + 2) * 17 / (3 + 6)

Il existe un certain potentiel pour que cela soit calculé en parallèle, mais il est logiquement limité. Je dirais qu'il n'y a aucun intérêt dans plus de deux threads, et même alors, ce ne sera généralement qu'un:

#1 a) 4 + 2 b) 6 * 17 c) 102 / 9
#2 a) 3 + 6

Le thread # 2 a contribué en calculant 3 + 6 = 9, utilisé à l'étape C par le thread # 1, en l'enregistrant d'une étape. Mais c'est dans la mesure où le parallélisme arrivera utilement ici. Alors que le thread # 2 pourrait calculer 17/9 tandis que # 1 fait 6 * 17, cela serait inutile, car vous avez maintenant deux chemins différents vers le même objectif qui ne peuvent pas être recombinés. C'est-à-dire, # 2 pourrait continuer à travailler:

b) 17 / 9 c) 1.888 * 6

Et se retrouvent avec le même résultat que le fil n ° 1 (11.333), mais ils ne se sont pas aidés au-delà de l'étape A, donc avoir deux d'entre eux poursuivre cet objectif est une perte de temps.

(Notez que cet exemple n'est pas littéral; il vise à démontrer un principe logique. L'échelle sur laquelle les tâches sont enfilées dans le code utilisateur est beaucoup plus grande, mais vous n'avez pas besoin d'une véritable leçon de programmation multithread pour saisir l'idée ici.)

L'exploitation de plusieurs processeurs nécessite du code écrit pour le faire. Vous ne pouvez pas simplement prendre quoi que ce soit et dire: "oh, utilisez les 4 cœurs et faites-le plus vite!". Ce n'est pas ce qui arriverait. Logiquement, beaucoup (..ou la plupart) des problèmes et des tâches impliquent des étapes qui ne peuvent pas se produire en parallèle, elles doivent se produire en séquence.


1. Mais voir le commentaire de Felix Dombek ci-dessous; Je ne suis pas un expert en IA. Il convient également de noter que, selon les commentaires de Peter Corde, les jeux d'instructions et les processeurs contemporains peuvent être exploités par le système d'exploitation pour optimiser les choses très finement de manière parallèle, et les pipelines matériels le font également, mais pas entre les cœurs (un seul core a plus d'une chose en cours, opérant sur le flux d'instructions à différents points avant leur exécution finale). J'essayais de m'en tenir au sujet des fils d'utilisateurs ici car je pense que c'est plus ou moins ce que vous voulez dire.

Boucles d'or
la source
4
J'ai écrit beaucoup de code numérique parallèle, et c'est un peu trompeur quant aux détails. Vous ne parallélisez pas au niveau d'opérations arithmétiques individuelles comme celle-ci. (Si nous nous étendons au-delà de Raspberry Pi, certains complieurs et processeurs vont déjà paralléliser une partie de cela même en dehors des structures de threading.) Vous parallélisez des tâches entières en plus gros morceaux.
Brick
4
@Brick "Vous ne parallélisez pas au niveau d'opérations arithmétiques individuelles comme celle-ci." -> Bien sûr que non, mais je vais préciser que c'est une analogie, pas une leçon sur la programmation multi-thread écrous et boulons.
goldilocks
4
Le parallélisme dans le calcul que vous utilisez comme exemple est si localisé qu'il créera un parallélisme au niveau des instructions dans un programme qui le calcule, et les processeurs avec une exécution dans le désordre peuvent exploiter ce parallélisme par eux-mêmes.
Peter Cordes
2
RPi3 utilise un dans l'ordre 2 à l' échelle superscalaire en.wikipedia.org/wiki/ARM_Cortex-A53 , donc avec la planification d'instruisant un compilateur peut encore exploiter le ILP en plaçant deux addinstructions à côté de l'autre afin qu'ils puissent à la fois exécuter dans le même cycle d'horloge. Le reste de multiplication et de division suivant sera sérialisé par des dépendances de données, cependant, comme vous le faites remarquer.
Peter Cordes
1
La détermination des parties parallélisables ne nécessite pas nécessairement une IA forte. Au sens «général», cela pourrait; mais on peut facilement imaginer que les ordinateurs pourraient utiliser une approche heuristique qui fonctionne principalement dans de nombreux cas pratiques. Par exemple, un ordinateur n'a pas prouvé le dernier théorème de Fermat, mais il existe certainement des programmes de démonstration de théorèmes. Notez que les compilateurs modernes pour les langages de programmation font déjà beaucoup de réarrangement de code dans le cadre de leurs étapes d'optimisation, ce qui implique de raisonner sur les parties parallélisables.
Felix Dombek
7

Non pour python.

D'autres personnes vous suggèrent de vous pencher sur le threading, qui est une réponse valide pour la plupart des langues, mais ils n'ont pas pris en compte le fait que vous utilisez python.

Le python GIL ne vous permet pas d'utiliser efficacement plusieurs cœurs.

Anon
la source
4
Le GIL rend légèrement plus difficile l' utilisation des 4 cœurs. En aucun cas, cela ne le rend impossible, ni même vraiment difficile.
Fake Name
5

L'utilisation de plusieurs cœurs nécessite d'exposer explicitement le parallélisme au niveau du thread au système d'exploitation, ce qui nécessite généralement que le programmeur écrive un programme multithread. (Ou pour exécuter un programme à thread unique plusieurs fois sur différentes entrées, comme la compilation avec make -j4)

Les compilateurs pour certaines langues prennent cependant en charge la parallélisation automatique. Par exemple, C ou C ++ avec OpenMP peut compiler une for()boucle ordinaire dans un programme qui démarre plusieurs threads.

#pragma omp parallel for
for(int i = 0; i < 1000000; ++i)
{
   A[i] = B[i] * constant + C[i];
}

Mais encore, cela doit se produire lorsque vous avez écrit ou compilé le programme. Il n'y a aucun moyen pour le matériel et les systèmes d'exploitation actuels d'utiliser plusieurs cœurs pour accélérer un programme à thread unique.


En relation: Comment un seul thread s'exécute-t-il sur plusieurs cœurs? : réponse: ils ne le font pas. Mais il existe d'autres types de parallélisme, comme le parallélisme au niveau de l'instruction, qu'un seul cœur de processeur trouve et exploite pour exécuter un seul thread plus rapidement qu'une instruction à la fois.

Ma réponse à cette question va dans certains détails sur la façon dont les processeurs modernes trouvent et exploitent le parallélisme fin au niveau des instructions. (Se concentrant principalement sur x86). Cela fait partie du fonctionnement normal des processeurs, en ayant plusieurs instructions en vol à la fois, et ce n'est pas quelque chose que vous devez activer spécialement. (Il existe cependant des compteurs de performances qui peuvent vous permettre de voir combien d'instructions par horloge votre processeur a réussi à exécuter lors de l'exécution d'un programme, ou d'autres mesures.)

Notez que RPi3 utilise des cœurs CPU ARM Cortex-A53 dans l'ordre . Chaque cœur est superscalaire à 2 larges (2 instructions par horloge comme ILP le permet), mais ne peut pas réorganiser les instructions pour trouver plus de parallélisme au niveau des instructions et masquer la latence.

Pourtant, le CPU est en pipeline, donc le nombre total d'instructions en vol (depuis la récupération et le décodage jusqu'à l'étape de réécriture à la fin du pipeline) est important. Lorsque les dépendances de données ne limitent pas les choses, il peut y avoir 2 instructions dans chaque étape de pipeline sur laquelle le processeur travaille, avec un débit de 2 instructions par horloge. (C'est ce que signifie 2-wide.)

Il ne peut pas exécuter des instructions dans le désordre, mais avec un ordre des instructions soigné (généralement par un compilateur), il peut toujours masquer la latence d'une instruction qui prend plusieurs cycles pour que sa sortie soit prête. (par exemple, une charge même si elle frappe dans le cache ou une multiplication prendra plusieurs cycles, contre un ajout étant prêt le cycle suivant). L'astuce consiste à ordonner les instructions asm afin qu'il y ait plusieurs instructions indépendantes entre celle qui produit un résultat et celle qui l'utilise.

Avoir un logiciel (un compilateur) pour planifier statiquement des instructions est plus fragile que d'avoir du matériel qui peut être réorganisé en interne tout en préservant l'illusion de fonctionner dans l'ordre du programme. Il est très difficile pour les compilateurs de faire un aussi bon travail que même une petite fenêtre en panne pour réorganiser les instructions car les échecs de cache sont imprévisibles, et il est difficile d'analyser les chaînes de dépendance entre les appels de fonction au moment de la compilation. Et le nombre de registres est limité sans changement de nom du registre matériel.


Tout cela est un petit confort lorsque votre code s'exécute plus lentement que vous le souhaitez. Bien sûr, il y a beaucoup de trucs sympas sous le capot dans un Cortex-A53, mais il y a plus de trucs sympas sous le capot dans un Cortex-A57 (comme l'exécution dans le désordre de jusqu'à 3 instructions par horloge), et encore plus dans un gros processeur x86 comme Skylake (sans parler des différences de vitesse d'horloge).

Le Cortex-A53 est assez fantastique par rapport à un https://en.wikipedia.org/wiki/Classic_RISC_pipeline comme le MIPS d'origine que vous découvrirez dans la classe d'architecture informatique, mais selon les normes modernes, c'est assez bas de gamme.

Peter Cordes
la source
1
"Il n'y a aucun moyen pour le matériel et les systèmes d'exploitation actuels d'utiliser plusieurs cœurs pour accélérer un programme à thread unique." n'est pas STRICTEMENT vrai. Par exemple, dans un programme Java à thread unique, Java peut faire tout son GC / analyse d'exécution / compilation sur des cœurs de processeur supplémentaires. L'analyse d'exécution est un gros problème car elle peut décider de faire des optimisations basées sur l'exécution de chemins de code sans rien coûter à votre "thread unique" et peut l'accélérer considérablement avec ce qu'elle apprend de l'analyse. En général, votre point est bon.
Bill K
@BillK Pour être honnête, le "programme" dans ce contexte ne l'est javapas myapp.jar, et il n'est certainement pas monothread.
goldilocks
1
Certes, je soulignais simplement que, selon la façon dont le runtime a été conçu, le "code que vous écrivez", même s'il est monothread, peut tirer parti de cœurs supplémentaires sans le coder explicitement en tant qu'application multithread. Python pourrait également fournir un runtime plus puissant, mais ce serait un peu inutile. Ce n'est pas un énorme saut de toute façon - je pense que même Java n'utilise qu'un demi-noyau supplémentaire pour aider avec une seule application filetée.
Bill K
" Il n'y a aucun moyen pour le matériel et les systèmes d'exploitation actuels d'utiliser plusieurs cœurs pour accélérer un programme à thread unique. " Et immédiatement après, vous expliquez comment le matériel exécute les instructions en parallèle.
Thomas Weller
3
@ThomasWeller Oui, mais pour être difficile, le pipelining de processeur n'utilise pas plusieurs cœurs; il est contenu dans un noyau, mais il permet de travailler sur plusieurs flux d'instructions. -À- dire, il est une forme de parallélisme, mais ce ne sont pas une forme de filetage à plusieurs noyaux.
goldilocks
4

Ce n'est pas du tout ainsi que fonctionnent les processeurs.

Dans l'état actuel des choses, votre processeur est parfaitement capable de fonctionner à 100% d'utilisation, en supposant qu'il n'est pas limité en raison de problèmes liés à la température à 80 degrés Celsius ou plus. Cela étant dit, vous ne voulez pas (généralement) voir votre CPU fixé à 100%. Si vous utilisez régulièrement 100% du processeur, vous en avez probablement trop pour votre processeur. Cela entraînera un bégaiement et une expérience utilisateur généralement malheureuse.

Pour comparer avec quelque chose de plus physique, votre utilisation du processeur ressemble beaucoup à une voiture. La voiture est probablement capable de parcourir 100 mph, mais il y a de fortes chances que votre compteur de vitesse lise quelque chose de manière significative en dessous. En ville, vous ne pourrez peut-être jamais obtenir environ 25 mph. Cela ne change cependant pas que la voiture peut aller à 100 mph. Vous n'avez tout simplement pas suffisamment appuyé sur l'accélérateur.

Si vous faites simplement que le RPi fasse plus de choses (poussez plus sur l'accélérateur), vous verrez le chiffre d'utilisation du CPU augmenter. Par exemple, surveillez l'utilisation du processeur lorsque vous exécutez la commande yesdans une fenêtre de terminal (n'oubliez pas que les ctrl+ccommandes de terminal sont terminées). Cela augmentera votre processeur de 25% car il maximise l'un de vos quatre cœurs de processeur.

Jacobm001
la source
5
Je pense que cette réponse est trompeuse, c'est-à-dire que vous ne voulez généralement pas que votre processeur fonctionne à 100%. Il existe de nombreuses applications à forte intensité numérique où vous souhaitez absolument une utilisation à 100% car vous avez dédié la ou les machines au calcul. Pour obtenir un vrai temps de supercalculateur, vous devez souvent prouver que votre code est suffisamment optimisé pour ce faire, sinon ils vous dénieront comme un gaspillage de ressources. Si vous avez un cluster Pi, vous n'obtenez pas de super performances informatiques, évidemment, mais cela pourrait rendre plus critique l'optimisation de l'utilisation, pas moins!
Brick
3
Je suis en quelque sorte d'accord avec Brick dans le sens où cela semble impliquer ici que si un processeur est à 25%, c'est parce que c'est pour conserver le gaz ou obéir à la limite de vitesse;) ou pour être poli et ne pas monopoliser les ressources. Vous voudrez peut-être préciser que c'est généralement parce que la tâche attend les E / S la plupart du temps. Les choses qui peuvent exécuter un seul noyau tout le long le seront. Ce qui (idéalement) empêche cela de perturber l'interface utilisateur, c'est la réduction du temps - mais en réalité, il est toujours assez facile de brouiller une petite machine monocœur.
goldilocks
L'utilisation à 100% du CPU ne provoque généralement pas une mauvaise UX. Même 1000% peut être suffisant car la plupart des programmes ne sont pas limités par le CPU mais par d'autres facteurs. Les seuls programmes qui deviennent lents en raison d'une charge CPU extrême sont les programmes qui utilisent en fait le CPU tout le temps.
Oskar Skog
4

Les autres réponses donnent de bons détails, mais ne semblent pas répondre spécifiquement à vos questions.

  1. Oui, si le programme (et le système d'exploitation) sont programmés pour prendre en compte plusieurs cœurs. («Threading» est le terme dans la programmation ici)
  2. La machine utilise autant ou aussi peu de chaque cœur que nécessaire pour terminer la tâche. il n'est donc pas nécessaire de changer quoi que ce soit.
  3. Vous pouvez définir des limites d'utilisation maximale, mais il n'est pas nécessaire de l'utiliser normalement. jetez un œil aux réponses ici: - /unix/151883/limiting-processes-to-not-exceed-more-than-10-of-cpu-usage

NB:

Si vous cherchez à améliorer les performances globales du pi, vous voudrez peut-être vous pencher sur l'overclocking. Cela permet au processeur de fonctionner à un rythme plus rapide. Les inconvénients sont une production de chaleur accrue, une durée de vie plus courte du processeur et une augmentation de la consommation d'énergie.

Stese
la source
2

Si possible, je paramétrerais le script et les exécuterais dans des processus Python séparés. Par exemple:

cat parameters.txt | xargs -n1 -P4 python run.py

Une autre alternative est la bibliothèque multiprocessing déjà mentionnée, qui vous permet de forker et de joindre des processus python. Mais cela nécessite également que vous ayez une liste de paramètres (comme un nom de fichier) pour lesquels vous souhaitez que les calculs soient exécutés.

NikoNyrh
la source
Première partie: Oui, présumer que le problème en question est embarrassamment parallèle .
Peter Mortensen
Ahaa vrai, je ne connaissais que le pool de traitement du multiprocessing mapmais apparemment il a aussi de nombreuses constructions de mémoire partagée assez sophistiquées.
NikoNyrh
1

Je pense que OP pourrait ne pas comprendre pleinement les concepts de la programmation multi-core / multi-thread et la difficulté d'utiliser pleinement 100% du multi-core à moins que l'algorithme puisse être facilement transformé en un problème parallèle embarrassant .

Pour plus d'informations, vous pouvez en savoir plus sur le titre bien connu de l'article «Le déjeuner gratuit est terminé» http://www.gotw.ca/publications/concurrency-ddj.htm

sonofusion82
la source
0

Si vous souhaitez tester votre RPI. Vous pouvez exécuter stresscomme ici , puis vous pouvez voir comment vos processeurs sont utilisés htop. Ceci est utile car vous pouvez voir si votre source d'alimentation est suffisante, si elle n'est pas suffisante, votre RPI essaiera d'utiliser trop de courant (ampérage) et il s'arrêtera.

D'un autre côté, si vous souhaitez utiliser des scripts python, vous devriez voir joblibce qui fonctionne très bien lorsque vous souhaitez paralléliser des processus, et donc vous utiliserez le nombre de processeurs que vous souhaitez.

silgon
la source
0

Bien que toutes ces réponses soient correctes de différentes manières, il est vrai que le système d'exploitation utilisera automatiquement les différents cœurs pour répartir la charge. Vous pouvez le voir avec un simple programme python (temp.py disons)

while True:
  x = 1.0

ouvrez un terminal à partir de votre bureau RPi et tapez $ topqui montrera le travail du processeur. Ouvrez ensuite un autre terminal et python3 temp.pyvous verrez une tâche python3 passer à 100% du temps processeur. Ensuite, ouvrez un autre terminal et répétez le processus et voyez comment vous vous déplacez jusqu'à 400%. Donc, à un certain niveau, comme l'a commenté @Shadow, c'est aussi simple que c'est la valeur par défaut. Cependant, la conception de programmes pouvant utiliser le traitement parallèle n'est pas anodine, comme d'autres l'ont expliqué.

paddyg
la source
0

La réponse est un oui retentissant! Vous devez simplement écrire votre programme pour les reconnaître et les utiliser. Les programmes qui font cela peuvent utiliser les cœurs. J'écris le mien pour le faire en Java et donc je peux.

Les réponses ci-dessus des développeurs Python ont un concept très limité de cette réponse et peuvent donc être très déroutantes mais la réponse est OUI et seulement OUI!

Orubel
la source
Pouvez-vous nous en dire plus?
SDsolar
0

Étant donné que l'OP n'a pas spécifié python dans sa question, je voudrais suggérer deux langages plus modernes qui fonctionnent bien sur le Raspberry Pi et ont des moyens très simples d'utiliser la concurrence.

Mon préféré actuel est la langue Rust. J'ai écrit et compilé des programmes sur le Pi. Rust est agréable en ce qu'il empêche de nombreux types de bogues de pointeurs et de conditions de concurrence, ce qui rend l'écriture de code simultané à la fois plus facile et plus sûre. Rust est un langage de programmation système, mais il peut faire à peu près tout ce que C peut faire.

Une autre langue de ce type est le Go (également appelé Golang pour faciliter la recherche). Go a été créé par l'équipe de Google et est une langue relativement mature. Il est facile de créer des coroutines dans Go, qu'ils appellent des «routines Go».

Ces deux langages peuvent compiler du code sur le Raspberry Pi, même le Pi Zero. Cependant, ils peuvent tous deux être compilés de manière croisée à partir d'un ordinateur plus rapide, ce qui est bien pour les gros programmes.

NomadMaker
la source