0

В программу загружаются ссылки из txt и добавляются в очередь. Далее нужно брать ссылку - переходить по ней и парсить значение online И последнее это склеить ссылку и ответ парсера. p/s : учу c# чуть больше недели, сильно не пиннайте )

Многопоточность я реализовал так:

for (int i = 1; i < load.Count; i++)
            {
                Thread myThread = new Thread(Proccess);
                myThread.IsBackground = true;
                myThread.Start();

код метода Process

public void Proccess()
        {
            string url;
            while (load.Count > 0)
            {
                lock (locks)
                {
                    var que = load.Dequeline();
                    url = que;
                }
                try
                {
                    hsettings.Reque(url);
                    Invoke((() =>
                    {
                    textBox1.AppendText(url + &quot; | &quot; + hsettings.online + '\r' + '\n');

                }));
            }

В результате я получаю

https://Myurl1 | 1000 online https://Myurl2 | 1200 online https://Myurl3 | 1000 online

Хотя в Myurl 3 online = 1500, но почему то был взят результат из Myurl1 И каждый запуск выводит разные данные. Я так понимаю, что из за неправильно реализации многопоточности.

Для более точной информации:

Метод Reque:

public void Reque(string line) \\ line берём из очереди
            {
                using (HttpRequest httpRequest = new()
                {
                    UserAgent = Http.RandomUserAgent(),
            AllowAutoRedirect = false,
         IgnoreProtocolErrors = true,
                   UseCookies = false,
        EnableEncodingContent = false,
                })
                try
                {

              var status = httpRequest.Get($&quot;{line}&quot;);

Мне нужно что-бы 10, 100 , 1000 url - без разницы сколько их будет, был получен ответ и из ответа надо достать информацию о кол-ве онлайн пользователей и склеить ссылку с этим кол-вом. Но у меня получается каша. lock пробовал, тоже самое.

Вопрос собственно вот в чём, как из потока сохранить полученную информацию ?

В List ?

Mundshtuk
  • 1
  • 1
  • https://ru.stackoverflow.com/a/752593/179763 ? – tym32167 Aug 31 '22 at 20:38
  • Там реализовано через async\await Хотелось бы понять как сделать тоже самое через thread – Mundshtuk Aug 31 '22 at 21:16
  • У вас объект hsettings один на все потоки получается, и все потоки меняют его состояние? Ну вот и получается, что вы печатаете из него значение в одном потоке, а в это время другой поток уже поменял его значение. Лучше использовать в разных потоках разные, не пересекающиеся объекты. А где используете одинаковые, там либо объекты должны быть специально для такого использования предназначены, либо надо делать lock, но слишком большой кусок кода под lock сведёт на нет всю пользу от многопоточности. – CrazyElf Sep 01 '22 at 06:18
  • 1
    Хотелось бы понять как сделать тоже самое через thread - зачем? И что такое Invoke? Winforms? Process - стандартный класс в .NET, вы бы переименовали, чтобы не путать людей. Что такое hsettings? Что такое load? По этому обрубку кода ничего не понятно. Покажите все недостающие части. – aepot Sep 01 '22 at 06:47
  • Вот тут ваша проблема: https://ru.stackoverflow.com/q/433887 – Pavel Mayorov Sep 01 '22 at 14:48
  • Да, там другой язык, но та же самая ошибка – Pavel Mayorov Sep 01 '22 at 14:48

2 Answers2

0

Для этого лучше использовать Parallel (кто-то может раскритиковать это, ибо принято использовать Task для web части)

private readonly ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 };
private int[] result;
public void Main()
{
    string path = @"C:\links.txt";
    string[] urls = File.ReadAllLines(path);
    result = new int[urls.Length];
    Parallel.For(0, urls.Length, parallelOptions, i => ParseUrl(i, urls[i]));
    for(int i = 0; i < urls.Length; i++)
        Console.WriteLine($"{urls[i]}: {result[i]}");
}
private void ParseUrl(int index, string url)
{
   var client = new HttpClient();
   int value = int.Parse(/*Какие-то действия, например можно скачать саму страницу и найти в ней значение.*/);
   result[i] = value;
}
Yotic
  • 859
  • Цитата: Хотелось бы понять как сделать тоже самое через thread – aepot Sep 01 '22 at 10:43
  • new WebClient() устарел, умер, закопан и разложился, и зачем он тут? – aepot Sep 01 '22 at 10:50
  • @aepot, изменил на HttpClient, как вы предлагаете реализовать нормальную систему через Thread? Делать свой замороченный ThreadPool? – Yotic Sep 02 '22 at 01:52
  • Это лучше у автора спросить, как я понял, его не особо заботит время на спавн потоков. – aepot Sep 02 '22 at 06:51
0

Узким местом был парсер кол-ва онлайн пользователей, а так-же запись этих данных в textbox.

Решение: обернуть в mutex:

var status = httpRequest.Get($"{url}");
                mutexObj.WaitOne();

                Respon = status.ToString();

                GetUrl = Parse(Respon, &quot;(?&lt;=online_users_id\&quot;&gt;).*?(?=&lt;/div&gt;)&quot;);

textBox1.BeginInvoke(() => { textBox1.AppendText($" {url} | {GetUrl}" + '\r' + '\n'); });

mutexObj.ReleaseMutex();

0xdb
  • 51,614
Mundshtuk
  • 1
  • 1