Problème avec les threads c#

Résolu/Fermé
Pouloucok - Modifié le 30 mai 2018 à 19:30
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 - 2 juin 2018 à 09:27
Bobjour,

Je suis bloqué depuis 2 jours sur un projet qui a pour but de vérifier l'existence d'un ou plusieurs dossiers dans une URL depuis un fichier texte.
(En gros j'ai une URL + un fichier texte avec tous les dossier à vérifier.)

Ce que j'ai fait, ça fonctionne avec un seul Thread sans soucis:
Pour lancer je fais:
           Thread thread1 = new Thread(new ThreadStart(A));
            thread1.Start();


<Foreach pour lire les lignes du fichier texte>
   foreach (string line in fichi)
                {
lien = le_site + line;
   var lixn = htcli.GetAsync(lien).Result;
                    page++;

                    add_c(list, "(" + page + "/" + page_tot + ") > " + lien, Color.Red);


                    if (lixn.StatusCode == HttpStatusCode.OK)
                    {
                        add_c(list, lien, Color.Green);
                    }
            
                }


Donc cela fonctionne avec un Thread mais si je veux par exemple que ça aille 2 fois plus vite, il faut rajouter un Thread et la le problème c'est qu'il ne m'affiche pas les résultats dans l’ordre du fichier texte.
Et pour vérifier que si déjà scanner j'aurai penser faire ça:

if(!dejascan.Contains(lien) {
//Et la le code ci-dessus
dejascan += lien;
}


Mais ça fait très brouillon et obsolète je pense.

Voila j'ai réduit le code le plus possible pour vous éviter une lecture inutile donc si il vous parais court c'est normal.

Je vous remercie d'avance pour vos réponses.
A voir également:

5 réponses

NHenry Messages postés 15113 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 22 avril 2024 331
Modifié le 30 mai 2018 à 19:37
Que les résultats se chevauchent c'est normal, les thread ne sont pas synchronisés.
Pour avoir une seule liste, il faudrait que tu utilise une System.Collection.Concurrent.ConcurrentQueue dans laquelle tu mette toutes tes lignes du fichier.
Ensuite, chaque thread ira piocher dans cette unique file, jusqu'à ce qu'il n'y ait plus rien dedans.

0
Merci pour ta réponse, Serait-il possible d'avoir un exemple ( sans forcément me mâché tout le travail )
Merci
0
NHenry Messages postés 15113 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 22 avril 2024 331
30 mai 2018 à 20:21
Je n'ai pas l'environnement sur mon ordi, mais en gros:
- Tu fais une instance (unique) de System.Collection.Concurrent.ConcurrentQueue dans laquelle tu mets toutes les lignes de ton fichier.
- Tu fais une instance System.Collection.Concurrent.ConcurrentQueue (ou ConcurrentList) pour les résultat
- Tu génères tes threads qui vont :
+ Puiser dans la collection précédemment créée
+ Faire du travail sur l'item récupéré
+ Retourner le résultat l'instance des résultats
+ Et recommencer jusqu'à ce que la file source soit vide

Les collections concurrentes (optimisées pour le threading et protégées contre les incohérences qui peuvent survenir dans ce mode) sont génériques (Classe<T>).
0
Pouloucok > NHenry Messages postés 15113 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 22 avril 2024
Modifié le 30 mai 2018 à 23:32
J'ai testé ceci:
        static string[] lines = File.ReadAllLines(@"fichier_texte.txt");
        static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(lines);




 foreach (string line in fichi)
                {
     string txt = string.Empty;
                if (queue.TryDequeue(out string resultat))
                {
                    txt = resultat;
                }
lien = le_site + txt;
   var lixn = htcli.GetAsync(lien).Result;
                    page++;

                    add_c(list, "(" + page + "/" + page_tot + ") > " + lien, Color.Red);


                    if (lixn.StatusCode == HttpStatusCode.OK)
                    {
                        add_c(list, lien, Color.Green);
                    }
}
}




Je suis désolé mais j'ai jamais utilisé le System.Collection.Concurrent.ConcurrentQueue, j'ai un peu de mal, Çà fonctionne, mais si je rajoute un Thread çà m'affiche tout en double, et si j'en rajoute un troisième ca m'affichetout en triple etc .. quel serait le meilleur moyen pour régler ça? Merci d'avance
0
Pouloucok > NHenry Messages postés 15113 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 22 avril 2024
Modifié le 31 mai 2018 à 01:01
EDIT:
J'en suis arrivé la ça fonctionne, mais c'est toujours dans le désordre:
 static string[] lines = File.ReadAllLines(@"fichier_texte.txt");
        static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(lines);


Et je lance mes Threads de cette manière: (2 Threads = pour aller 2 fois plus vite)
  th = new Thread(() => verif(list,lox));
            th.Start();
  th1 = new Thread(() => verif(list,lox));
            th1.Start();


 while (queue.TryDequeue(out number))
                {
  var lixn = htcli.GetAsync(solo + number).Result;
                page++;

                  add_c(list, "(" + page + "/" + page_tot + ") > " + lien, Color.Red);


                    if (lixn.StatusCode == HttpStatusCode.OK)
                    {
                        add_c(list, lien, Color.Green);
                    }
}


Je bloque vraiment la, merci d'avance !
0
Ok ça marche merci, je vais regardé ça de suite ! je vous tiens au courant.
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
30 mai 2018 à 21:37
0
Bonsoir, merci pour ta réponse, je regarde ça.
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4
1 juin 2018 à 00:28
UP + EDIT

Bonjour,

J'ai un projet qui a pour but de vérifier l'existence d'un ou plusieurs dossiers dans une URL (httpclient) depuis un fichier texte.

Pour récupérer les lignes du fichier texte j'ai fait ça:
static string[] lines = File.ReadAllLines(@"fichier_texte.txt");
 static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(lines);


while (queue.TryDequeue(out number))
                {
  var lixn = htcli.GetAsync(solo + number).Result;
                page++;

                  add_c(list, "(" + page + "/" + page_tot + ") > " + lien, Color.Red);


                    if (lixn.StatusCode == HttpStatusCode.OK)
                    {
                        add_c(list, lien, Color.Green);
                    }
}


En gros il va m'afficher en rouge si le dossier n'existe pas, et en vert si il existe dans une listbox.

Mon problème c'est que j'aimerais ajouter plusieurs threads au lieu d'un seul pour que la vérification aille plus vite. Ça fonctionne, mais il ne m'affiche pas les résultats dans l'ordre.


Ex:
Fichier texte:
/dossier1
/dossier2
/dossier3

Résultats:
http://www.url.com/dossier2
http://www.url.com/dossier1
http://www.url.com/dossier3

Comment faire pour que les résultats soit dans l'ordre ?

Merci d'avance pour vos réponses.

(j'ai refait le sujet au propre ici)
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
1 juin 2018 à 07:09
Est ce que tu as lu les 4 tutos que je t'ai proposés?
Il y a un passage sur le chainage des taches.
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4
1 juin 2018 à 07:35
Salut, oui j'ai regardé j'ai fait plusieurs tentatives mais sans succès..
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4
Modifié le 1 juin 2018 à 08:16
Même en reprenant le code sur le tuto pour le travailler ça ne fonctionne pas,

   public partial class Form1 : Form
    {
        static int numberOfThreads = 10;
        static int number = 1;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Task<bool>[] tasks = new Task<bool>[numberOfThreads];
            for (int i = 0; i < numberOfThreads; ++i)
            {
                int j = i;
                checked
                {
                    tasks[i] = Task<bool>.Run(() => { return IsPrimeInRange(number, number * j / numberOfThreads, number * (j + 1) / numberOfThreads); });
                }
            }

            Task.WaitAll(tasks);
        }

        private static bool IsPrimeInRange(long number, long start, long end)
        {
            for (long i = Math.Max(start, 2); i < end; i = ++i)
            {
                if (number % i == 0L)
                {
                  MessageBox.Show("");
                }
            }

            return true;
        }

    
    }


Pourrais-tu me mettre sur une piste ?
merci
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
1 juin 2018 à 10:04
Je n'ai jamais été confronté à ce type de besoin de synchronisation.
J'ai juste pensé que le pool de thread pouvait être une solution pour toi.
Comme tu n'avais pas dit que ça n'allait pas je t'ai demandé.
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
1 juin 2018 à 18:08
Ça marche merci quand même
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
1 juin 2018 à 18:38
Peux tu montrer le code de la méthode add_c?
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4
Modifié le 1 juin 2018 à 18:50
Oui,
  public static void add_c(RichTextBox rich string text, Color color, bool pi = true)
        {
            rich.Invoke((Action)delegate
            {

                rich.SelectionStart = rich.TextLength;
                rich.SelectionLength = 0;

                if(pi == true)
                {
                    rich.SelectionColor = Color.Gray;
                    rich.AppendText(">< ");
                } 

                rich..SelectionColor = color;
                rich.AppendText(text + Environment.NewLine);
                rich.SelectionColor = box.ForeColor;

                rich.ScrollToCaret();

            });
        }

C'est pour ajouter le texte dans un richtextbox !
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
1 juin 2018 à 21:13
Ton erreur est d'utiliser un contrôle pour stocker un résultat.
Un contrôle ça sert à afficher le contenu d'une source de données.


Tu écris une classe, avec 2 propriétés : une string pour le texte et une couleur.
    public class TexteEnCouleur
    {
        public string Texte { get; set; }

        public Color Couleur { get; set; }
    }


Tu appliques ce qu'NHenri t'a dit, à savoir une utiliser une ConcurrentList (enfin ConcurrentBag, à priori List n'existe pas dans le framework, mais on en trouve le net) pour stocker le résultat.

Et c'est le contenu de ce sac que tu affiches dans ton RichTextBox, après l'avoir trié


while (queue.TryDequeue(out number))
                {
  var lixn = htcli.GetAsync(solo + number).Result;
                page++;

                  add_c(list, "(" + page + "/" + page_tot + ") > " + lien, Color.Red);


                    if (lixn.StatusCode == HttpStatusCode.OK)
                    {
                        //add_c(list, lien, Color.Green);
                       monSacConcurrent.Add(new TexteEnCouleur { Texte = "LeTexte", Couleur = Color.Green  });
                       AfficheResultat();
                    }
}


        private void AfficheResultat()
        {
            rich.Invoke((Action)delegate
            {

                rich.Clear();
                List<TexteEnCouleur> listeTriee = monSacConcurrent.OrderBy(x => x.Texte).ToList();

                foreach(TexteEnCouleur texte in listeTriee)
                {
                    //ici le code pour remplir le richtextbox
                }

            });
        }


Je n'ai pas essayé mais ça devrait le faire.
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4
1 juin 2018 à 21:59
Merci pour ta réponse,
J'ai créer un nouveau projet pour comprendre un peu mieux, alors j'ai fait:

static string[] lines = File.ReadAllLines(@"text_file.txt");
     static HttpClient http = new HttpClient();
        static string number;
        static int page = 0;
        static ConcurrentBag<string> myBag = new ConcurrentBag<string>(lines);
        static int page_tot = myBag.Count();

        public class TexteEnCouleur
        {
            public  string Texte { get; set; }

            public Color Couleur { get; set; }
        }


 private void AfficheResultat()
        {
            richTextBox1.Clear();
            List<TexteEnCouleur> listeTriee = myBag.OrderBy(x => x.Texte).ToList();

            foreach (TexteEnCouleur texte in listeTriee)
            {
                //ici code pour remplir le richtextbox
            }

        }


 private void scan()
        {
                       string lien = "http://www.google.fr/";
            while (myBag.TryTake(out number))
            {
                var lixn = http.GetAsync(lien + number).Result;
                page++;

                richTextBox1.AppendText("(" + page + "/" + page_tot + ") > " + lien);


                if (lixn.StatusCode == HttpStatusCode.OK)
                {
                    myBag.Add(new TexteEnCouleur { Texte = "LeTexte", Couleur = Color.Green });
                    AfficheResultat();
                }
            }


Après essai j'ai ça:


1er screen:
Conversion impossible de 'WindowsFormsApp10.Form1.TexteEnCouleur' en 'string'

2ème screen:
String' ne contient pas de définition pour 'Texte' et aucune méthode d'extension 'Texte' acceptant un premier argument de type 'string' n'a été trouvée



Je comprends pas la ou ça bloque..
Merci d'avance
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 931
1 juin 2018 à 22:07
Ben oui, myBag ne doit pas être une collection de string mais une collection de TexteEnCouleur
0
Ikikiki Messages postés 29 Date d'inscription jeudi 31 mai 2018 Statut Membre Dernière intervention 11 juin 2018 4 > Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024
1 juin 2018 à 22:34
Voila le final:
namespace WindowsFormsApp10
{
    public partial class Form1 : Form
    {
        static string[] lines = File.ReadAllLines(@"text_file.txt");
        static HttpClient http = new HttpClient();
        static string number;
        static int page = 0;
        static ConcurrentBag<TexteEnCouleur> myBag = new ConcurrentBag<TexteEnCouleur>();
        static ConcurrentQueue<string> queue = new ConcurrentQueue<string>(lines);
        static int page_tot = myBag.Count();

        public class TexteEnCouleur
        {
            public  string Texte { get; set; }

            public Color Couleur { get; set; }
        }

        private void AfficheResultat()
        {
            richTextBox1.Clear();
            List<TexteEnCouleur> listeTriee = myBag.OrderBy(x => x.Texte).ToList();

            foreach (TexteEnCouleur texte in listeTriee)
            {
                //ici le code pour remplir le richtextbox
            }

        }

        public Form1()
        {
            InitializeComponent();
        }

        private void gogo()
        {
            string lien = "http://www.google.fr/";
            while (queue.TryDequeue(out number))
            {
                var lixn = http.GetAsync(lien + number).Result;
                page++;
                richTextBox1.Invoke((Action)delegate
                {
                    richTextBox1.AppendText("(" + page + "/" + page_tot + ") > " + lien + number + Environment.NewLine);
                });

                if (lixn.StatusCode == HttpStatusCode.OK)
                {
                    myBag.Add(new TexteEnCouleur { Texte = "LeTexte", Couleur = Color.Black });
                    AfficheResultat();
                }
            }

        }

     

        private void button1_Click(object sender, EventArgs e)
        {
           // Vitesse x3
            Task.Factory.StartNew(() => { gogo(); });
            Task.Factory.StartNew(() => { gogo(); });
            Task.Factory.StartNew(() => { gogo(); });

        }
    }
}


Mais toujours le même soucis
0