[C#] Wielowątkowość a wielordzeniowość

Witam

Wpadł mi do głowy taki pomysł (prawie usnąłem czekając aż program przemieli dane), aby wykorzystać trochę moc procesora do przetwarzania plików. Mam program który przemielenia multum danych i przy mieleniu wykorzystuje 25% procesora (4 rdzenie), lub koło 8 (12 rdzeni). Utworzyłem sobie program który generuje mi zadaną liczbę wątków, dzieli dane na porcje ale teraz, jak odpalić każdy wątek w innym rdzeniu? Czy jest jakaś prosta metoda? Ktoś coś próbował?

Pozdrawiam

Witam,

Proponuję zapoznać się z biblioteką TPL dostępną w .NET 4.

Wiele przykładów na: http://msdn.microsoft.com/en-us/library/dd460693.aspx

Pozdrawiam!

Ewentualnie z klasą ThreadPool http://www.dotnetperls.com/threadpool (zarówno TPL jak i ThreadPool będzie dobrym rozwiązaniem). Ogólnie jest tak, że Ty nie musisz myśleć o tym jak przydzielić dany wątek do danego rdzenia. To już jest robione za Ciebie w tle.

ThreadPool będzie dla Ciebie bardzo dobrym rozwiązaniem…

Tworzysz pulę wątków i nie musisz martwić się który wątek wykona się na którym rdzeniu - to system operacyjny ma za zadanie tak porozdzielać wątki, aby uzyskać jak najlepszą wydajność, równomierne obciążenie poszczególnych rdzeni itp…

Pozdrawiam

matzu a mógłbyś podać jakieś przykład? Wiadomo, na przykładach najlepiej widać wszystko.

Ja w swoim kodzie mam tablicę wątków

Thread[] watki = new Thread[Ilość_wątków];

Czy da się to jakoś łatwo podpiąć pod to co polecacie? Tak najlepiej żebym nie musiał kodu działania samych wątków zmieniać. Bo przyznam się nie miałem czasu przestudiować.

Przykłady znajdziesz chociażby na stronach msdn (lub w linku, który podałem). Mimo wszystko przygotowałem przykładowy programik, który IMO powinien kilka kwestii wyjaśnić :slight_smile: Program oblicza kilka silni w osobnych wątkach - zarówno przy użyciu Thread Pool jak i TPL (do metody obliczającej silnię dodałem wstrzymanie bieżącego wątku na dwie 2ms, żeby zasymulować dłuższą operację - możesz zobaczyć jakie będą wyniki, gdy zmienisz wartość z 2ms na np. 1ms lub 5ms). Program ten wstrzymuje działanie dopóki wszystkie silnie nie zostaną obliczone. Dopiero, gdy wszystkie silnie zostaną wyliczone, program wyświetla wyniki (w takiej kolejności w jakiej wywołane zostały poszczególne wątki) i kontynuuje swoje działanie.

using System;

using System.Diagnostics;

using System.Threading;

using System.Threading.Tasks;


namespace ParallelProgrammingDemo

{

    internal class Program

    {

        private static Random random = new Random(DateTime.Now.Millisecond);


        private static void Main(string[] args)

        {

            int[] numbers = new int[50];

            for (int i = 0; i < numbers.Length; i++)

                numbers[i] = random.Next(1, 20); // 

            Stopwatch watch = new Stopwatch();

            watch.Start();

            Result[] results = CalculateFactorials(numbers);

            watch.Stop();

            Console.WriteLine("--- Single-threaded programming ---");

            Display(results);

            Console.WriteLine("Elapsed milliseconds: {0}.\n", watch.ElapsedMilliseconds.ToString());


            watch.Reset();

            watch.Start();

            results = CalculateFactorialsWithThreadPool(numbers);

            watch.Stop();

            Console.WriteLine("--- Parallel programming - ThreadPool ---");

            Display(results);

            Console.WriteLine("Elapsed milliseconds: {0}.\n", watch.ElapsedMilliseconds.ToString());


            watch.Reset();

            watch.Start();

            results = CalculateFactorialsWithTPL(numbers);

            watch.Stop();

            Console.WriteLine("--- Parallel programming - TPL ---");

            Display(results);

            Console.WriteLine("Elapsed milliseconds: {0}.\n", watch.ElapsedMilliseconds.ToString());


            Console.ReadKey();

        }


        private static Result[] CalculateFactorials(int[] numbers)

        {

            Result[] results = new Result[numbers.Length];


            for (int i = 0; i < numbers.Length; i++)

            {

                Result result = new Result(numbers[i]);

                result.Factorial = CalculateFactorial(result.Number);


                results[i] = result;

            }


            return results;

        }


        private static Result[] CalculateFactorialsWithThreadPool(int[] numbers)

        {

            ManualResetEvent[] resetEvents = new ManualResetEvent[numbers.Length];

            Result[] results = new Result[numbers.Length];


            for (int i = 0; i < numbers.Length; i++)

            {

                ManualResetEvent resetEvent = new ManualResetEvent(false);

                Result result = new Result(numbers[i]);


                resetEvents[i] = resetEvent;

                results[i] = result;


                ThreadPool.QueueUserWorkItem(delegate

                {

                    result.Factorial = CalculateFactorial(result.Number);

                    resetEvent.Set();

                });

            }


            WaitHandle.WaitAll(resetEvents);


            return results;

        }


        private static Result[] CalculateFactorialsWithTPL(int[] numbers)

        {

            Result[] results = new Result[numbers.Length];


            int from = 0;

            int to = numbers.Length;


            Parallel.For(from, to, index =>

                {

                    Result result = new Result(numbers[index]);

                    result.Factorial = CalculateFactorial(result.Number);


                    results[index] = result;

                });


            return results;

        }


        private static void Display(Result[] results)

        {

            Console.WriteLine("{0,-10} {1,-10}", "Number", "Factorial");

            foreach (Result result in results)

                Console.WriteLine("{0,-10} {1,-10}", result.Number, result.Factorial);

        }


        private static long CalculateFactorial(long value)

        {

            checked

            {

                if (value == 0)

                {

                    Thread.Sleep(2);

                    return 1;

                }

                else

                    return value * CalculateFactorial(value - 1);

            }

        }

    }


    internal class Result

    {

        public Result(int number)

        {

            Number = number;

            Factorial = 0;

        }


        public int Number { get; private set; }

        public long Factorial { get; set; }

    }

}