Решение интеграла методом прямоугольников, используя многопоточность C#

Здравствуйте, дорогие форумчане))) Имеется вот такая простенькая прога, в которой нужно реализовать многопоточность и средства синхронизации. Подскажите,пожалуйста, как это можно сделать :slightly_smiling_face:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//////////
    class Program
    {
           public static double a=1, b=2.6;
           public static int  n=10000;
            static double LeftRectangle(Func<double, double> f, double a, double b, int n)
            {
                var h = (b - a) / n;
                var sum = 0d;
                for (var i = 0; i <= n - 1; i++)
                {
                    var x = a + i * h;
                    sum += f(x);
                }

                var result = h * sum;
                return result;
            }

            static double RightRectangle(Func<double, double> f, double a, double b, int n)
            {
                var h = (b - a) / n;
                var sum = 0d;
                for (var i = 1; i <= n; i++)
                {
                    var x = a + i * h;
                    sum += f(x);
                }

                var result = h * sum;
                return result;
            }

            static double CentralRectangle(Func<double, double> f, double a, double b, int n)
            {
                var h = (b - a) / n;
                var sum = (f(a) + f(b)) / 2;
                for (var i = 1; i < n; i++)
                {
                    var x = a + h * i;
                    sum += f(x);
                }

                var result = h * sum;
                return result;
            }
              static double Fun(double x)
             {
            double rez = x / (Math.Sqrt(x * x + 3));
            return rez;
              }
        static void Main(string[] args)
            {
       
                double f(double x) => Fun(x);

                var result = LeftRectangle(f,a , b, n);
                Console.WriteLine("Формула левых прямоугольников: {0}", result);
                result = RightRectangle(f, a,b, n);
                Console.WriteLine("Формула правых прямоугольников: {0}", result);
                result = CentralRectangle(f, a, b, n);
                Console.WriteLine("Формула средних прямоугольников: {0}", result);

                Console.ReadKey();
            }
        }
 
}

Thread, Task/TPL, async/await, … В C# много вариантов.

https://www.learncsharptutorial.com/threading-and-types-of-threading-stepbystep.php
Overview of synchronization primitives | Microsoft Docs

Да я вроде бы понимаю как это должно выглядеть, но как конкретно для этой проги можно это использовать, т.е. чтобы было не бессмысленно, а как-то для оптимизации. Что именно лучше поделить по потокам? Методы вычисления или может число разбиений?

Просто вот конкретно в задании стоит разбиение на 10000, для чего тут можно вообще использовать потоки?)

Task t1 = Task.Factory.StartNew(() =>
            {
                var result = LeftRectangle(f, a, b, n);
                Console.WriteLine("Формула левых прямоугольников: {0}", result);
            });
            Task t2 = Task.Factory.StartNew(() =>
            {
                var result = RightRectangle(f, a, b, n);
                Console.WriteLine("Формула правых прямоугольников: {0}", result);
            });
            Task t3 = Task.Factory.StartNew(() =>
            {
                var result = CentralRectangle(f, a, b, n);
                Console.WriteLine("Формула средних прямоугольников: {0}", result);
            });

            Task.WaitAll(t1, t2, t3);

Можно и вот так

А сам цикл можно и так распаралелить. На примере первой функции:

static double LeftRectangle(Func<double, double> f, double a, double b, int n)
        {
            var h = (b - a) / n;
            var sum = 0d;       
                Parallel.For(0, n, new Action<int>((i) =>
                {
                    var x = a + i * h;
                    sum += f(x);
                }));

            var result = h * sum;
            return result;
        }

Только это не дает ощутимого выигрыша:

image

Причем без распаралеливания даже быстрее получилось. В скобках среднее время выполнения функции в мс. Цикл из 1000 выполнений, разбиений N = 100000

1 лайк

Лучше значение возвращать. Выводить из разных потоков без синхронизации обычно не стоит.

		var t1 = Task.Factory.StartNew<double>(() =>
		{
			return LeftRectangle(f, a, b, n);
		});
		
		Task.WaitAll(t1, t2, t3);
		
		Console.WriteLine("Формула левых прямоугольников: {0}", t1.Result);
1 лайк

Благодарю, очень помогли))

Спасибо за подсказку))