J'écris actuellement un encodeur et je veux (évidemment) le rendre rapide.

J'ai un système de travail pour faire l'encodage (donc chaque goroutine fait la même chose) mais j'ai du mal à trouver la bonne quantité de goroutines pour exécuter le code. CPU occupé.

Les pensées suivantes m'ont traversé l'esprit :

  • Si un fichier ne fait que <1 ko, il n'est pas utile d'exécuter le code dans de nombreuses goroutines
  • La quantité de goroutines doit être influencée par les noyaux/fils disponibles
    • exécuter 16 goroutines sur un processeur 4x4 GHz ne sera pas un problème, mais qu'en est-il avec un processeur 4x1 GHz ?
    • difficile à déterminer de manière fiable multiplateforme
  • Le processeur doit être occupé mais pas autant que pour empêcher les autres programmes de répondre (~ 70 % ?)
    • difficile à décider à l'avance en raison de la vitesse d'horloge et d'autres paramètres

Maintenant, j'ai essayé de décider en fonction de ces facteurs du nombre de goroutines à utiliser, mais je ne sais pas trop comment le faire sur plusieurs plates-formes et de manière fiable.

Tentatives déjà faites :

  • utiliser une fonction linéaire pour déterminer en fonction de la taille du fichier
    • nécessite différentes fonctions basées sur le processeur
  • analyse des spécifications du processeur à partir de lscpu
    • pas multiplateforme
    • nécessite une autre fonction à déterminer en fonction de la fréquence

Qui n'ont pas été satisfaisants.

-1
poldi1405 28 janv. 2020 à 00:47

1 réponse

Meilleure réponse

Vous mentionnez dans un commentaire que

chaque goroutine lit le fichier à encoder

Mais bien sûr, le fichier—n'importe quel fichier—est déjà codé d'une manière ou d'une autre : en texte brut, peut-être, ou en UTF-8 (flux d'octets), peut-être assemblé en unités de « lignes ». Ou il peut s'agir d'un flux d'images, tel qu'un fichier mpeg, composé d'un certain nombre d'images. Ou il peut s'agir d'une base de données, constituée d'enregistrements. Quelle que soit sa forme d'entrée, elle contient une sorte d'unité de base que vous pouvez alimenter votre (ré-)encodeur.

Cette unité, quelle qu'elle soit, est un lieu judicieux pour diviser le travail. (Comment sensé, dépend de ce que c'est. Voir l'idée de couper ci-dessous.)

Disons que le fichier se compose de lignes indépendantes : utilisez alors scanner.Scan pour les lire, et passez chaque ligne à un canal qui prend des lignes. Spin off N, pour certains N, lecteurs qui lisent la chaîne, une ligne à la fois :

ch := make(chan string)
for i := 0; i < n; i++ {
    go readAndEncode(ch)
}

// later, or immediately:
for s := bufio.NewScanner(os.Stdin); s.Scan(); {
    ch <- s.Text()
}
close(ch)

S'il y a 100 lignes et 4 lecteurs, les quatre premières opérations ch <- s.Text() vont vite, et la cinquième s'arrête jusqu'à ce qu'un des lecteurs ait fini d'encoder et reprenne la lecture du canal.

Si les lignes individuelles sont une unité trop petite, vous devriez peut-être lire un "morceau" (par exemple, 1 Mo) à la fois. Si le morceau a une ligne partielle à la fin, sauvegardez ou lisez plus, jusqu'à ce que vous ayez une ligne entière. Envoyez ensuite l'intégralité du bloc de données.

Étant donné que les canaux copient les données, vous souhaiterez peut-être envoyer une référence au morceau à la place.1 Cela serait vrai pour toute unité de données plus grande. (Les lignes ont tendance à être courtes, et la surcharge de leur copie n'est généralement pas très importante par rapport à la surcharge de l'utilisation des canaux en premier lieu. Si vos lignes ont le type string, eh bien, consultez la note de bas de page.)

Si la ligne, ou un morceau de ligne, n'est pas l'unité de travail correcte ici, déterminez ce qu'est est. Considérez les goroutines comme des personnes (ou des petits gaufres occupés) qui ont chacune un travail à faire. Ils peuvent dépendre de quelqu'un d'autre – une autre personne ou un spermophile – pour faire un travail plus modeste, quel qu'il soit ; et avoir dix personnes, ou gaufres, travaillant sur des sous-tâches permet à un superviseur de les gérer. Si vous devez effectuer le même travail N fois et que N n'est pas illimité, vous pouvez créer N goroutines. Si N est potentiellement illimité, créez un nombre fixe (peut-être basé sur #cpus) et alimentez-les via un canal.


1

3
torek 28 janv. 2020 à 05:17