@Anton2001

Как добавить многопоточность в этот код?

Здравствуйте , такая задача . Есть код который работает в один поток . Как правильно добавить возможность многопоточности чтоб увеличить скорость работы ?
Исходный код https://drive.google.com/file/d/1_ku66JJ4FWuiwIUk7...

Была такая идея , сделать List и добавлять в него строки из цикла . А потом сделать функцию которая будет дёргать из списка строки и обрабатывать их . Запускать функцию в 20-30 потоках .
Но тут была ошибка так как строк слишком много и List не выдерживает (у меня 16 оперативы) и крашится . Вообщем нужна помощь , что только не пробовал .
  • Вопрос задан
  • 102 просмотра
Пригласить эксперта
Ответы на вопрос 4
firedragon
@firedragon
Senior .NET developer
Кода не видел но делайте так
Выбирайте аргументы и добавляйте задачи в массив задач
После используйте Task.WaitAll(taskSrray)
Ответ написан
@vabka Куратор тега C#
Токсичный шарпист
Уберите ссылку на гуглодиск - никто не будет пытаться найти в вашем архиве обсуждаемый код.

Если строк много - обрабатывайте их не все сразу, а потоком.
Используйте для этого каналы из System.Threading.Channgels
Количество одновременных потоков должно быть равно количеству ядер - иначе прироста никакого не будет.
Ответ написан
@Anton2001 Автор вопроса
Вот код
textBox1.Text = "12foa9f";
string key = "";
        char StartChar = '1';
        bool lifeWork = false;
        int line = 0, success = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            key = textBox1.Text;
            StartChar = Convert.ToChar(textBox1.Text.Substring(0, 1));
            timerLog.Interval = 900;
            timerLog.Enabled = true;
            lifeWork = true;
            Thread thr = new Thread(Work);
            thr.Start();
        }
        private void Work()
        {
            long value = EncodeBase36(key);
 
            while (lifeWork)
            {
                long newValue = value - 1;
                if (StartChar != Convert.ToChar(DecodeBase36(newValue).Substring(0, 1)))
                {
                    break;
                }
                line++;
                GetResponce(DecodeBase36(newValue));
                value = newValue;
            }
            MessageBox.Show("Off work");
        }
 
        private void GetResponce(string value)
        {
            // Тут будет происходить гет запрос на сайт с использованием value и прочая работа с строкой . По времени занимает от 5 до 15 секунд.
            // Так что код сделла чисто для симуляции времени работы .
            Random rnd = new Random();
            int timeOutn = rnd.Next(5, 15);
            Thread.Sleep(timeOutn * 1000);
            success++;
        }
        public static long EncodeBase36(string number, int radix = 36)
        {
            const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
            if (radix < 2 || radix > Digits.Length)
                throw new ArgumentException("The radix must be >= 2 and <= " +
                    Digits.Length.ToString());
 
            if (String.IsNullOrEmpty(number))
                return 0;
 
            // Make sure the arbitrary numeral system number is in upper case
            number = number.ToUpperInvariant();
 
            long result = 0;
            long multiplier = 1;
            for (int i = number.Length - 1; i >= 0; i--)
            {
                char c = number[i];
                if (i == 0 && c == '-')
                {
                    // This is the negative sign symbol
                    result = -result;
                    break;
                }
 
                int digit = Digits.IndexOf(c);
                if (digit == -1)
                    throw new ArgumentException(
                        "Invalid character in the arbitrary numeral system number",
                        "number");
 
                result += digit * multiplier;
                multiplier *= radix;
            }
 
            return result;
        }
 
        private void timerLog_Tick(object sender, EventArgs e)
        {
            lbLine.Text = line.ToString();
            lbSuccess.Text = success.ToString();
        }
 
        public static string DecodeBase36(long decimalNumber, int radix = 36)
        {
            const int BitsInLong = 64;
            const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
            if (radix < 2 || radix > Digits.Length)
                throw new ArgumentException("The radix must be >= 2 and <= " +
                    Digits.Length.ToString());
 
            if (decimalNumber == 0)
                return "0";
 
            int index = BitsInLong - 1;
            long currentNumber = Math.Abs(decimalNumber);
            char[] charArray = new char[BitsInLong];
 
            while (currentNumber != 0)
            {
                int remainder = (int)(currentNumber % radix);
                charArray[index--] = Digits[remainder];
                currentNumber = currentNumber / radix;
            }
 
            string result = new String(charArray, index + 1, BitsInLong - index - 1);
            if (decimalNumber < 0)
            {
                result = "-" + result;
            }
 
            return result;
        }
Ответ написан
@none7
Создаёшь функцию c yield return для перечисления всех чисел. Создаёшь Semaphore(30, 30). Затем перебирая эти числа foreach блокируешь семафор(один из 30 слотов) и запускаешь таски, которые по завершению семафор освобождают. Но нужно не забыть, что, выход из foreach не означает завершение всех задач, а так же не стоит забывать про синхронизацию.
Как то так:
spoiler

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string key = "";
        char StartChar = '1';
        bool lifeWork = false;
        int line = 0, success = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            key = textBox1.Text;
            StartChar = Convert.ToChar(textBox1.Text.Substring(0, 1));
            timerLog.Interval = 100;
            timerLog.Enabled = true;
            lifeWork = true;
            _ = Work();
        }

        IEnumerable<long> GetWorks(string key)
        {
            long value = EncodeBase36(key);

            while (true)
            {
                long newValue = value - 1;
                if (StartChar != Convert.ToChar(DecodeBase36(newValue).Substring(0, 1)))
                {
                    break;
                }
                yield return newValue;
                value = newValue;
            }
        }
        private async Task Work()
        {
            var set = new HashSet<Task>();
            var jobsSim = new SemaphoreSlim(30, 30);
            var lockSim = new SemaphoreSlim(1, 1);

            foreach(var value in GetWorks(key))
            {
                if (!lifeWork) break;

                // ограничиваем число потоков
                // по большей части лимит нужен, чтобы не зафлудить сервер запросами
                await jobsSim.WaitAsync();
                Task task = GetResponce(DecodeBase36(value));
                await lockSim.WaitAsync();
                set.Add(task);
                lockSim.Release();
                _ = task.ContinueWith(async(t) => {
                    await lockSim.WaitAsync();
                    success++;
                    set.Remove(t);
                    lockSim.Release();
                    jobsSim.Release();
                });
                line++;
            }

            await lockSim.WaitAsync();
            var tasks = set.ToList();
            lockSim.Release();

            await Task.WhenAll(tasks);

            MessageBox.Show("Off work");
        }
        private async Task GetResponce(string value)
        {
            // Тут будет происходить гет запрос и прочая работа с строкой . По времени занимает от 5 до 15 секунд.
            // Так что код сделла чисто для симуляции времени работы .
            Random rnd = new Random();
            int timeOutn = rnd.Next(5, 15);
            await Task.Delay(timeOutn * 1000);
        }
        public static long EncodeBase36(string number, int radix = 36)
        {
            const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            if (radix < 2 || radix > Digits.Length)
                throw new ArgumentException("The radix must be >= 2 and <= " +
                    Digits.Length.ToString());

            if (String.IsNullOrEmpty(number))
                return 0;

            // Make sure the arbitrary numeral system number is in upper case
            number = number.ToUpperInvariant();

            long result = 0;
            long multiplier = 1;
            for (int i = number.Length - 1; i >= 0; i--)
            {
                char c = number[i];
                if (i == 0 && c == '-')
                {
                    // This is the negative sign symbol
                    result = -result;
                    break;
                }

                int digit = Digits.IndexOf(c);
                if (digit == -1)
                    throw new ArgumentException(
                        "Invalid character in the arbitrary numeral system number",
                        "number");

                result += digit * multiplier;
                multiplier *= radix;
            }

            return result;
        }

        private void timerLog_Tick(object sender, EventArgs e)
        {
            lbLine.Text = line.ToString();
            lbSuccess.Text = success.ToString();
        }

        public static string DecodeBase36(long decimalNumber, int radix = 36)
        {
            const int BitsInLong = 64;
            const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            if (radix < 2 || radix > Digits.Length)
                throw new ArgumentException("The radix must be >= 2 and <= " +
                    Digits.Length.ToString());

            if (decimalNumber == 0)
                return "0";

            int index = BitsInLong - 1;
            long currentNumber = Math.Abs(decimalNumber);
            char[] charArray = new char[BitsInLong];

            while (currentNumber != 0)
            {
                int remainder = (int)(currentNumber % radix);
                charArray[index--] = Digits[remainder];
                currentNumber = currentNumber / radix;
            }

            string result = new String(charArray, index + 1, BitsInLong - index - 1);
            if (decimalNumber < 0)
            {
                result = "-" + result;
            }

            return result;
        }
    }
}

Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
от 1 200 до 3 500 $
Itiviti Санкт-Петербург
До 230 000 ₽
АЛМАЗ Москва
от 90 000 до 180 000 ₽