J'ai créé un programme qui compte les occurrences d'une chaîne cible dans un fichier. Il est censé utiliser le parallélisme pour accomplir cela, mais je n'arrive pas à comprendre comment écrire run () pour n'évaluer qu'une partie du fichier afin qu'un thread différent de celui-ci puisse évaluer le reste du fichier. Au moins, c'est ma compréhension du parallélisme. Je suis dans la documentation et je regarde des vidéos depuis quelques jours et j'ai vraiment besoin que quelqu'un me l'explique; pas comment résoudre pas à pas mon problème particulier en soi, mais expliquer le multi-threading en utilisant quelque chose de plus qu'une méthode principale avec une boucle qui imprime l'identifiant du thread. Je sais que ma classe doit implémenter Runnable et que run () doit être remplacé. Je ne sais pas comment je suis censé écrire run () pour ne traiter qu'une partie du fichier lorsque je ne peux pas lui transmettre de paramètres.
public static void main(String[] args) {
new Thread(new Test()).start();
new Thread(new Test()).start();
System.out.println("My program counts: " + Test.getTotal() + " occurences of 'the'.");
}
}
public class Test implements Runnable {
private File alice = new File(getCurrentDir() + "/alice.txt");
private String[] words;
private BufferedReader reader;
private StringBuilder sb;
private int count;
private static int total;
public void run() {
getAlice();
for(int i = 0; i < words.length; i++) {
if(words[i].toLowerCase().equals("the")) {
count++;
}
}
total = count;
}
public void getAlice() {
try{
reader = new BufferedReader(new FileReader(alice));
sb = new StringBuilder();
String line = "";
while((line = reader.readLine()) != null) {
sb.append(line);
}
words = sb.toString().split(" ");
} catch (IOException e) {
e.printStackTrace();
}
}
public String getCurrentDir() {
String currDir = System.getProperty("user.dir");
return currDir;
}
public String[] getWords() {
return words;
}
static int getTotal() {
return total;
}
}```
3 Réponses :
En gros, vous l'avez bien fait avec Threads mais en sortie, vous devez prendre des valeurs de l'instance.
NEW ... RUNNABLE ... BLOCKED 0.7175015787267744 0.6915288485156048 0.777565206934673 RUNNABLE ... TERMINATED_0.777565206934673
En savoir plus sur le total int statique privé n'est pas statique!
Exemple plus simple
public class MyT implements Runnable {
double d;
public static void main(String[] args)
{
MyT myt = new MyT();
Thread t1 = new Thread(myt);
t1.start();
while(t1.getState() != Thread.State.TERMINATED)
{
System.out.println(t1.getState());
}
System.out.println(t1.getState()+"_"+myt.getD());
}
@Override
public void run() {
for(int i=0;i<3;i++)
{
d = Math.random();
System.out.println(d);
}
}
public double getD()
{
return d;
}
Sortie
Test t1 = new Test();
Thread th = new Thread(t1);
th.start();
//wait till Thread_th finish run method
while(th.getState() != Thread.State.TERMINATED)
{
//Thread-states
//New, Runnable, Blocked, Waiting, Timed Waiting, Terminated
}
System.out.println(t1.getTotal());
Je ne sais pas trop ce que signifient les commentaires dans la boucle while
vous devez regarder sur Thread doc. Un thread a certains états (fonctionnant comme un automate fini). Lorsque démarrer Thread , vous devez attendre que la méthode d'exécution soit terminée. Ensuite, vous pouvez obtenir le calcul. Regardez sur OUTPUT. J'obtiens D seulement après la fin de l'exécution, cela signifie que T.state est TERMINÉ.
Thead n'obtient pas le résultat immédiatement. Il faut du temps pour que s'exécute pour terminer . Vérifiez donc pendant lorsque Thread est terminé ( state is TERMINATED )
t1.join fait la même chose que while (t1.getState ()! = Thread.State.TERMINATED) : Wait_for_run_to_finish. La join est préférable, mais l'une ou l'autre peut être utilisée avec le même résultat.
Sans moyen de diviser le fichier proprement, cela serait difficile à faire: le fractionnement arbitraire du fichier pourrait diviser les mots.
Si le fichier est divisé en lignes, et si les lignes ne séparent jamais les mots, cela nous donne quelque chose avec quoi travailler.
Une conception aurait un seul fil de lecture et un pool de fils de comptage de mots.
Le thread de lecture obtiendrait un thread de comptage arrêté, obtiendrait le tampon de lecture de ce thread, lisait la ligne suivante dans le tampon, puis reprendrait le thread de comptage.
Un thread de comptage parcourrait son tampon de lecture, qui contiendrait une seule ligne de texte, et finirait par ajouter le nombre de mots sur la ligne au total du nombre de mots global. Après avoir terminé, un thread de comptage se remettrait dans le pool de threads disponibles.
Le fait qu'il s'agisse d'un gain de performance dépendra du temps relatif passé à faire des E / S par rapport au temps passé à compter les mots. Le comptage des mots peut être tellement plus rapide que l'IO que le parallélisme n'accélère pas le traitement et pourrait même ralentir les choses en raison de la surcharge de gestion des threads.
Alternativement, si le fichier a déjà été lu et divisé en lignes, ce qui signifierait que IO n'est pas inclus dans les performances, alors des gains de performances pourraient être obtenus.
De plus, combien de threads et si le nombre de threads a pris une ou plusieurs lignes importerait probablement.
Comment suis-je censé écrire
run ()pour ne traiter qu'une partie du fichier lorsque je ne peux pas lui passer de paramètres?Vous pouvez transmettre des paramètres, mais vous les transmettez au constructeur
Test, qui les enregistre ensuite dans des champs, pour que la méthoderun ()les utilise. p >// Create threads Test test0 = new Test(0); Test test1 = new Test(1); Thread thread0 = new Thread(test0); Thread thread1 = new Thread(test1); // Start threads thread0.start(); thread1.start(); // Wait for threads to end thread0.join(); thread1.join(); // Now we can print result here int total = test0.getTotal() + test1.getTotal(); System.out.println("My program counts " + total + " occurrences of 'the'.");
Vous ne devez pas appeler
getTotal ()tant que le thread n'a pas fini de traiter le fichier.Pour attendre le thread pour terminer, appelez
join ().Vous ne devez pas non plus utiliser
staticpour le total.public class Test implements Runnable { private final int partToProcess; public Test(int partToProcess) { this.partToProcess = partToProcess; } @Override public void run() { // use this.partToProcess here } }Si vous souhaitez diviser le fichier en plus de deux parties, vous devez utiliser des tableaux pour stocker les instances
TestetThread.
Pour lire la seconde moitié d'un fichier, vous ne pouvez pas utiliser un
FileReader.Voir par exemple question " Comment lire un fichier à partir d'un certain décalage en Java? " pour en savoir plus.
Notez que la lecture à partir de 2 positions différentes dans un fichier en même temps ralentira le traitement, sauf si vous utilisez un SSD, car un bras de disque dur normal ne peut pas être à deux endroits en même temps. En tant qu'exercice de multi-threading, c'est bien, mais en réalité, vous ne voudriez probablement pas faire cela.
Notez également que lorsque vous divisez un fichier en deux par taille de fichier, vous probablement diviser le texte du fichier au milieu d'un mot, et si le fichier texte utilise un codage multi-octets comme UTF-8, vous pourriez même diviser les octets d'un caractère, vous devez donc ajouter du code pour détecter et contourner ce problème.
Files.lines (Path.of (System.getProperty ("user.dir"), "alice.txt")). parallel (). mapToInt (l -> l.split ("") .count). somme ();