powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Парралельный обход коллекции в строгом порядке с заданным числом потоков
25 сообщений из 90, страница 2 из 4
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542658
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabas,
Извини, свой проект есть.
Готовый код альтруисты бывают, но редко.
Удачи!
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542662
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabas
Код: c#
1.
2.
3.
4.
5.
...
            tasks[i] = Task.Run(() =>
            {
               _semaphore.Wait();
...


ИМХО Не очень хорошая идея повисать на Wait() внутри таска. Этим ты поток занимаешь из трэдпула.

Лучше при старте запустить 4 таска, а внутри таска цикл: извлечь очередной необсчитанный элемент taskList[] и обсчитать. Т.е. тасков столько, сколько надо потоков.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542663
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как вариант
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
        public class MyIndexer
        {
            int _currix = -1;
            public int GetNext()
            {
                lock (this) {
                    _currix++;
                    return _currix;
                }
            }
        }
        static void Main(string[] args)
        {
            var dts = new List<DateTime>();
            var rnd = new Random();
            for (int i = 0; i < 100; i++)
                dts.Add(DateTime.Now.AddDays(-100.0 * rnd.NextDouble()));
            dts = dts.OrderBy(i => i).ToList();
            var indexer = new MyIndexer();
            var tasks = new List<Task>();
            for (int i = 0; i < 4; i++) {
                var taskid = i + 1;
                var startix = indexer.GetNext();
                tasks.Add(Task.Run(() => {
                    var ix = startix;
                    while (ix < dts.Count) {
                        Console.WriteLine("{0} - {1} - task{2}", ix, dts[ix], taskid);
                        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(rnd.NextDouble())); // обработка...
                        ix = indexer.GetNext();
                    }
                }));
                while (tasks.Last().Status == TaskStatus.WaitingToRun)
                    System.Threading.Thread.Sleep(1); // лучше не придумал, как упорядочить старт
            }
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("The end.");
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542666
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123barrabas,
В оракле JOB на своём ЯП.
Делай.
как на plsql и джобах сделать я знаю.
но в данном конкретном случае мне нужно консольное приложение, которое будет запускаться в существующей инфраструктуре (принимать определенные уже параметры из вне, писать лог в нужном формате и т.д.), со своим шедулером, который все это обеспечивает, который умеет прибивать приложения, а останавливать джобы нет.
если отдать все в БД, то убив приложение, процесс не остановится.
в общем, есть готовая инфраструктура работающая и данная нам в ощущениях и выбор решения обусловлен именно этим.
Я конечно ценю советы, серьёзно, но вопрос был именно про дотнет.
как я уже сказал, что найденное решение может тиражироваться и на сторонние web-сервисы
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542670
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЛучше при старте запустить 4 таска, а внутри таска цикл: извлечь очередной необсчитанный элемент taskList[] и обсчитать. Т.е. тасков столько, сколько надо потоков.
Тоже так подумал, но возникает (небольшая) проблема на старте (см.код выше)
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542672
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tbarrabas
Код: c#
1.
2.
3.
4.
5.
...
            tasks[i] = Task.Run(() =>
            {
               _semaphore.Wait();
...


ИМХО Не очень хорошая идея повисать на Wait() внутри таска. Этим ты поток занимаешь из трэдпула.

Лучше при старте запустить 4 таска, а внутри таска цикл: извлечь очередной необсчитанный элемент taskList[] и обсчитать. Т.е. тасков столько, сколько надо потоков.
понятно, такой вариант описывал выше, но почему-то остановился не на нем.
наверное действительно будет лучше.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542673
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123barrabas,
Извини, свой проект есть.
Готовый код альтруисты бывают, но редко.
Удачи!
да без проблем. спасибо
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542685
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
так всего 4 потока.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
   static int _pcount = 0;
      static object _lock = new object();
      
      static int PCount
      {
         get
         {
            lock (_lock)
            {
               return ++_pcount;
            }
         }
      }

      class PTaskTestItem
      {
         public int OrderNum;
         public int SleepSec;
         public int RunNum;

         public PTaskTestItem(int orderNum, int sleepSec)
         {
            OrderNum = orderNum;
            SleepSec = sleepSec;
            RunNum = -1;
         }

         public override string ToString()
         {
            return string.Format("{0} - {1} [{2}]", OrderNum, RunNum, SleepSec);
         }
      }

      public void Test3()
      {
         var taskList = new List<PTaskTestItem>()
         {
            new PTaskTestItem(1, 10),
            new PTaskTestItem(2, 5),
            new PTaskTestItem(3, 3),
            new PTaskTestItem(4, 8),
            new PTaskTestItem(5, 12),
            new PTaskTestItem(6, 7),
            new PTaskTestItem(7, 10),
            new PTaskTestItem(8, 8),
            new PTaskTestItem(9, 10),
            new PTaskTestItem(10, 4),
            new PTaskTestItem(11, 1),
            new PTaskTestItem(12, 3),
            new PTaskTestItem(13, 10),
            new PTaskTestItem(14, 12),
            new PTaskTestItem(15, 11),
            new PTaskTestItem(16, 4),
            new PTaskTestItem(17, 7),
            new PTaskTestItem(18, 6),
            new PTaskTestItem(19, 10),
            new PTaskTestItem(20, 14),
         };
         var po = new ParallelOptions() { MaxDegreeOfParallelism = 4 };
        
         var tasks = new Task[po.MaxDegreeOfParallelism];
         for (int i = 0; i < po.MaxDegreeOfParallelism; i++)
         {
            tasks[i] = Task.Run(() =>
            {
               while (true)
               {
                  var n = PCount;
                  var x = taskList.FirstOrDefault(f => f.OrderNum == n);
                  if (x == null)
                     break;
                  x.RunNum = n;
                  Thread.Sleep(x.SleepSec * 1000);
                  Debug.WriteLine(x.ToString());
               }
            });
         }

         Task.WaitAll(tasks);
}



все в свою очередь запустились (return string.Format("{0} - {1} [{2}]", OrderNum, RunNum, SleepSec);)
3 - 3 [3]
2 - 2 [5]
4 - 4 [8]
1 - 1 [10]
6 - 6 [7]
5 - 5 [12]
8 - 8 [8]
7 - 7 [10]
10 - 10 [4]
11 - 11 [1]
12 - 12 [3]
9 - 9 [10]
16 - 16 [4]
13 - 13 [10]
14 - 14 [12]
15 - 15 [11]
17 - 17 [7]
18 - 18 [6]
19 - 19 [10]
20 - 20 [14]
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542686
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRDima TЛучше при старте запустить 4 таска, а внутри таска цикл: извлечь очередной необсчитанный элемент taskList[] и обсчитать. Т.е. тасков столько, сколько надо потоков.
Тоже так подумал, но возникает (небольшая) проблема на старте (см.код выше)
Потому что ты неправильно это написал
Код: c#
1.
2.
3.
4.
                var startix = indexer.GetNext();
                tasks.Add(Task.Run(() => {
                    var ix = startix;
...


надо так
Код: c#
1.
2.
                tasks.Add(Task.Run(() => {
                    var ix = indexer.GetNext();


В этом случае не надо дожидаться кто раньше стартанет, т.к. первый запустившийся начнет выполнять первое задание.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542689
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TВ этом случае не надо дожидаться кто раньше стартанет, т.к. первый запустившийся начнет выполнять первое задание.
Нет Дима, первый запустившийся не обязательно успеет взять первое задание, в этом то и проблема...
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542692
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRDima TВ этом случае не надо дожидаться кто раньше стартанет, т.к. первый запустившийся начнет выполнять первое задание.
Нет Дима, первый запустившийся не обязательно успеет взять первое задание, в этом то и проблема...
Внимательно посмотри на код 20903233
Я не про первого созданного, а именно про первого запустившегося. Номер первого задания надо получать внутри таска, а не снаружи. В этом проблема твоего кода.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542698
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TВнимательно посмотри на код 20903233
Я не про первого созданного, а именно про первого запустившегося. Номер первого задания надо получать внутри таска, а не снаружи. В этом проблема твоего кода.
Так как ты предлагаешь у меня было с самого начала, результат мне не понравился, т.к. я не про "первого запустившегося", а про "первого запускаемого", понимаешь?
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542708
Pu4koff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Объясните дураку чем не подходит
Код: c#
1.
Parallel.Foreach(<ConcurrentQueue>, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => {})
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542720
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pu4koffОбъясните дураку чем не подходит
Код: c#
1.
Parallel.Foreach(<ConcurrentQueue>, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => {})


у еее

всем подходит
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542732
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pu4koffОбъясните дураку чем не подходит
Код: c#
1.
Parallel.Foreach(<ConcurrentQueue>, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => {})


+5 Вроде именно для таких.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542743
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

вот как еще можно решить проблему со стартом (сигнализировать из задания, когда оно "подхватило" свой первый номер)
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
            var startEvent = new System.Threading.AutoResetEvent(true);
            for (int i = 0; i < 4; i++) {
                var taskid = i + 1;
                startEvent.Reset();
                tasks.Add(Task.Run(() => {
                    var ix = indexer.GetNext();
                    startEvent.Set();
                    while (ix < dts.Count) {
                        Console.WriteLine("{0} - {1} - task{2}", ix, dts[ix], taskid);
                        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(rnd.NextDouble())); // обработка...
                        ix = indexer.GetNext();
                    }
                }));
                startEvent.WaitOne();
            }
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542811
refreg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pu4koffОбъясните дураку чем не подходит
Код: c#
1.
Parallel.Foreach(<ConcurrentQueue>, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => {})

Нет гарантии, что будет в нужном порядке.

Метод AsOrdered
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542827
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LRDima T,

вот как еще можно решить проблему со стартом (сигнализировать из задания, когда оно "подхватило" свой первый номер)
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
            var startEvent = new System.Threading.AutoResetEvent(true);
            for (int i = 0; i < 4; i++) {
                var taskid = i + 1;
                startEvent.Reset();
                tasks.Add(Task.Run(() => {
                    var ix = indexer.GetNext();
                    startEvent.Set();
                    while (ix < dts.Count) {
                        Console.WriteLine("{0} - {1} - task{2}", ix, dts[ix], taskid);
                        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(rnd.NextDouble())); // обработка...
                        ix = indexer.GetNext();
                    }
                }));
                startEvent.WaitOne();
            }


Зачем лишний тормоз? Не надо тут никакой синхронизации.
Похоже тебя смущает что Console.WriteLine() отрабатывает не так как ты ожидаешь. Это проблема вызова Console.WriteLine() и не более того. Замени Console.WriteLine() на добавление в ConcurrentQueue<string> и в конце выведи содержимое.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542828
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
refreg,
Дак в него нужно отдавать коллекцию на одну дату.
Иначе вообще никакой параллельности.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542830
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Т.с. бы ещё таймштамп ввёл и просил очерёдности выполнения)).
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542839
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЗачем лишний тормоз? Не надо тут никакой синхронизации.
Похоже тебя смущает что Console.WriteLine() отрабатывает не так как ты ожидаешь. Это проблема вызова Console.WriteLine() и не более того. Замени Console.WriteLine() на добавление в ConcurrentQueue<string> и в конце выведи содержимое.
Да нет же)) Гипотетически "строгость" может быть необходимой и на старте по номерам заданий/потоков, т.е., чтобы задание/поток№1 обрабатывал первый элемент, №2 - второй, и т.д. Вот я и "усилил" условие задачки (больше из эстетических соображений), чтобы не было стартовой "путаницы", когда, к примеру, первый елемент хватает задание/поток№3, а №1 достается второй элемент... Впрочем, спорить что правильно а что нет не имеет смысла, т.к. мы не знаем зачем ТСу такой "строгий порядок".
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542982
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
какой поток из пула запустит первую дату не важно. важно чтобы моментом старта обработки у меньшей даты был меньше или равен следующей по порядку.
а причина довольна простая, чтобы можно было остановить процесс обработки и точно сказать, что обработалось от сих до сих, а а не в разнобой.
до этого код был написан немного не оптимально, бралось нужное кол-во дат и запускалось одновременно, дожидались код-да все завершаться, потом следующая партия. получалалось что потоки какое-то время простаивают, тк время обработки может быть разным.
вот заметил и решил исправить.
переписал на Parallel.Foreach(<ConcurrentQueue>, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => {})
погонял тесты, вроде все норм, хотя тут есть комент что порядок не гарантирован.
по идее для получения элемента из очереди используется спецметоды, а foreach может использовать просто IEnumerable, тогда хз, гарантируется ли соблюдение очереди?
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542985
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
время обработки разное но не кардинально, т.е. первая дата не будет обрабатываться когда уже в другом потоке обрабатывается 20я. поэтому допустимо такое упрощение имеет право на .. и опять же есть готовая инфраструктура запуска приложения и управления параметрами. ну и опять же прерывать и перезапускать будет человек и читать лог тоже.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542986
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabas,
Так условие очерёдности в параллельной работе ты сам выдумал?
Заняться тебе нечем.
...
Рейтинг: 0 / 0
Парралельный обход коллекции в строгом порядке с заданным числом потоков
    #39542987
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabasпрерывать и перезапускать будет человек и читать лог тоже.
Вот и приведи задачу с точки зрения пользователя, а не ту что ты сам придумал.
...
Рейтинг: 0 / 0
25 сообщений из 90, страница 2 из 4
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Парралельный обход коллекции в строгом порядке с заданным числом потоков
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]