Spouštění vláken v cyklu   zodpovězená otázka

C#, Threading

Zdravím,

předem se omlouvám za triviální otázku, ale nedokážu nikde na webu najít vzorový příklad jakou cestou se ubrat (mám v tom guláš co vůbec použít - Threads, BackgroundWorker, Parallel.For or ForEach Loop apod.)

Současný stav:

Spouštím konzolovou aplikaci, ve které načtu data z DB. V cyklu (foreach nebo for) čtu jednotlivé položky, ke kterým dále zjišťuji dodatečné informace.

Cílový stav:

Abych toto zpracování urychlil, chtěl bych docílit stavu, kdy aplikaci (parametrem) řeknu, kolik max. může využít vláken. Dokud aplikace čte data v cyklu, spusť nové vlákno pro každý cyklus, ale max. do počtu např. MaxVlaken=10. Jakmile nějaké vlákno doběhne, tak pokračuj spuštěním dalšího vlákna.

Nepotřebuji řešit "ukončení právě běžícího procesu" - v nouzi stačí kill procesu aplikace. Jediné co potřebuji je počkat na další běh programu po ukončení všech vláken.

Nástin kódu:

int MaxPocetVlaken = 10;
DataTable = DotazDoDB;

foreach(DataRow in DataTable.Rows)
{
  if(SoucasneVlakno <= MaxPocetVlaken)
  {
    Thread myThread = new Thread();
    myThread.Run(ZpracujDaleData());
  }
  else
   CekejNezNejakeVlaknoBudeVolneAPakPokracuj
}

ZpracujDalsiKodPoDokonceniVsechVlaken();

Děkuji, Petr

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Já bych na Vašem místě použil Task Parallel Library, dlouhotrvající úkoly probíhají ve třídě Task a pomocí Task.WaitAll metody si počkáte na ukončení všech vláken. Na MSDN je velmi hezký příklad toho, co mám (a pravděpodobně i Vy) na mysli:

http://msdn.microsoft.com/en-us/library/...

Idea je taková, že si vytvoříte pole Tasků a pak toto pole předáte funkci WaitAll, která vyhodnotí, kolik z Tasků už se dokončilo (úspěšně či neúspěšně) a počká na dokončení ostatních. Probíhá to v try-catch konstrukci, protože pokud některý Task selže, zapíše se výjimka do AggregateException, kterou můžete odchytit.

A ještě mě napadá, že jednodušší může být použití Parallel.Invoke. Této funkci předáte pole delegátů a ona se pokusí je provést paralelně. Jak je patrné z dokumentace, počet delegátů nutně nemusí odpovídat počtu vytvořených vláken, probíhají tam optimalizace pro nejlepší výkon.

http://msdn.microsoft.com/en-us/library/... Parallel.Invoke

http://msdn.microsoft.com/en-us/library/... Overload umožňující omezit maximální počet vláken

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Zdravím,

děkuji a zároveň se omlouvám za pozdní reakci, ale chtěl jsem se prvně seznamít a vyzkoušet jednotlivé přístupy. Nejvíce mi vyhovuje přístup "Task.WaitAll Method (Task[])" ale nemůžu se na MSDN ani googlu dopátrat následujících informací (rád bych to pochopil).

1) Pokud vytvořím několik tasků, dostávám výstup např.:

Task=35, i=34, TickCount=444971323, Thread=6

Task=36, i=35, TickCount=444972135, Thread=17

Task=37, i=36, TickCount=444972431, Thread=13

Task=38, i=37, TickCount=444972837, Thread=11

Task=39, i=38, TickCount=444973539, Thread=12

Task=40, i=39, TickCount=444974521, Thread=18

Task=41, i=40, TickCount=444974724, Thread=16

Task=42, i=41, TickCount=444974927, Thread=14

Task=43, i=42, TickCount=444975223, Thread=15

Nechápu ani při krokování, jak jsou Threads tvořené, tj. mám Thread=1 až Thread=63, a nemám je omezené na max. 10 zaráz spuštěných threadů (vytěžuje procesor).

2) Pokud dojde k vyjímce "throw new InvalidOperationException("SIMULATED EXCEPTION");" tak v debug módu tato vyjímka se mi zobrazí (jak jsem pochopil z dokumentací, měla by být skrytá a měla by se zachytit až v AggregateException)

Děkuji, Petr

Pro úplnost přikládám zdrojový kód:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class WaitAllDemo
    {
        // Demonstrated features: 
        // 		Task.Factory 
        //		Task.Result 
        //		Exception handling 
        // Expected results: 
        // 		10 tasks are started, each passed an index as a state object. 
        //		The tasks that receive an argument between 2 and 5 throw exceptions. 
        //		Task.WaitAll() wraps all exceptions in an AggregateException and propagates it to the main thread. 
        // Documentation: 
        //		http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory_members(VS.100).aspx 
        //      http://msdn.microsoft.com/en-us/library/system.threading.tasks(v=vs.100).aspx
        //      http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.waitall.aspx
        //      http://msdn.microsoft.com/en-us/library/dd537609.aspx
        //      http://stackoverflow.com/questions/10044099/is-there-a-generic-task-waitall
        //      http://reedcopsey.com/2010/07/19/parallelism-in-net-part-18-task-continuations-with-multiple-tasks/
        //      http://www.wintellect.com/cs/blogs/jlikness/archive/2011/06/27/using-the-task-parallel-library-tpl-for-events.aspx
        static void Main()
        {
            // Exceptions thrown by tasks will be propagated to the main thread 
            // while it waits for the tasks. The actual exceptions will be wrapped in AggregateException. 
            try
            {

                // Define a delegate that prints and returns the system tick count
                Func<object, int> action = (object obj) =>
                {
                    int i = (int)obj;

                    // Make each thread sleep a different time in order to return a different tick count
                    Thread.Sleep(i * 100);

                    // The tasks that receive an argument between 2 and 5 throw exceptions 
                    if (2 <= i && i <= 5)
                    {
                        // neprobubla skryte do AggregateException
                        throw new InvalidOperationException("SIMULATED EXCEPTION");
                    }

                    int tickCount = Environment.TickCount;
                    Console.WriteLine("Task={0}, i={1}, TickCount={2}, Thread={3}", Task.CurrentId, i, tickCount, Thread.CurrentThread.ManagedThreadId);

                    return tickCount;
                };

                // BACHA, DEFINUJE POČET ÚLOH, NE POČET MAX. SPUŠTĚNÝCH VLÁKEN
                const int n = 1500;

                // Construct started tasks
                Task<int>[] tasks = new Task<int>[n];
                for (int i = 0; i < n; i++)
                {
                    tasks[i] = Task<int>.Factory.StartNew(action, i);
                }

                // Wait for all the tasks to finish.
                Task.WaitAll(tasks);

                // We should never get to this point
                Console.WriteLine("WaitAll() has not thrown exceptions. THIS WAS NOT EXPECTED.");
            }
            catch (InvalidOperationException ex3)
            {
                // pokus o skryte odchyceni InvalidOperationException
                Console.WriteLine("\n-------------------------------------------------\n{0}", ex3.ToString());
            }
            catch (AggregateException e)
            {
                // seznam vsech chyb v jednotlivych vlaknech
                Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)");
                for (int j = 0; j < e.InnerExceptions.Count; j++)
                {
                    Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
                }
            }
            catch (Exception e2)
            {
                // obecne nezachycene vyjimky
                Console.WriteLine("\n-------------------------------------------------\n{0}", e2.ToString());
            }

            // pridrz vypis (jen pro debug)
            Console.ReadLine();
        }

    }
}

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback