C# 用TPL加速pi的计算

C# 用TPL加速pi的计算,c#,parallel-processing,task-parallel-library,C#,Parallel Processing,Task Parallel Library,我需要使用任务并行库通过Monte Carlo方法计算Pi数,但当我的并行程序运行时,它计算Pi数的时间比它的非并行模拟长得多。两个如何修复它?并行计算类及其非并行模拟如下: class CalcPiTPL { Object randLock = new object(); int n; int N_0; double aPi; public StringBuilder Msg; // diagonstic

我需要使用任务并行库通过Monte Carlo方法计算Pi数,但当我的并行程序运行时,它计算Pi数的时间比它的非并行模拟长得多。两个如何修复它?并行计算类及其非并行模拟如下:

class CalcPiTPL
    {
        Object randLock = new object();
        int n;
        int N_0;
        double aPi;
        public StringBuilder Msg; // diagonstic message
        double x, y;
        Stopwatch stopWatch = new Stopwatch();

        public void Init(int aN)
        {
            stopWatch.Start();
            n = aN; // save total calculate-iterations amount
            aPi = -1; // flag, if no any calculate-iteration has been completed
            Msg = new StringBuilder("No any calculate-iteration has been completed");
        }
        public void Run()
        {
            if (n < 1)
            {
                Msg = new StringBuilder("Inbalid N-value");
                return;
            }

            Random rnd = new Random(); // to create randomizer
            Task[] tasks = new Task[4];
            tasks[0] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
            tasks[1] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
            tasks[2] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
            tasks[3] = Task.Factory.StartNew(() => PointGenerator(n, rnd));
            Task.WaitAll(tasks[0], tasks[1], tasks[2], tasks[3]);

            aPi = 4.0 * ((double)N_0 / (double)n); // to calculate approximate Pi - value
            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
            Console.WriteLine("RunTime " + elapsedTime);
        }
        public double Done()
        {
            if (aPi > 0)
            {
                Msg = new StringBuilder("Calculates has been completed successful");
                return aPi; // return gotten value
            }
            else
            {
                return 0; // no result
            }
        }
        public void PointGenerator(int n, Random rnd)
        {
            for (int i = 1; i <= n / 4; i++)
            {
                lock (randLock)
                {
                    x = rnd.NextDouble(); // to generate coordinates
                    y = rnd.NextDouble(); // 

                    if (((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) < 0.25)
                    {
                        //Interlocked.Increment(ref N_0); 
                        N_0++; // coordinate in a circle! mark it by incrementing N_0
                    }
                }
            }
        }
    }
class CalcPiTPL
{
Object randLock=新对象();
int n;
int N_0;
双aPi;
公共StringBuilder Msg;//诊断消息
双x,y;
秒表秒表=新秒表();
公共void Init(int-aN)
{
秒表。开始();
n=aN;//保存总计算迭代次数
aPi=-1;//标志,如果没有完成任何计算迭代
Msg=新的StringBuilder(“未完成任何计算迭代”);
}
公开募捐
{
if(n<1)
{
Msg=新的StringBuilder(“有效N值”);
返回;
}
Random rnd=new Random();//创建随机化器
任务[]任务=新任务[4];
tasks[0]=Task.Factory.StartNew(()=>PointGenerator(n,rnd));
tasks[1]=Task.Factory.StartNew(()=>PointGenerator(n,rnd));
tasks[2]=Task.Factory.StartNew(()=>PointGenerator(n,rnd));
tasks[3]=Task.Factory.StartNew(()=>PointGenerator(n,rnd));
Task.WaitAll(任务[0]、任务[1]、任务[2]、任务[3]);
aPi=4.0*((双精度)N_0/(双精度)N);//计算近似Pi值
秒表;
TimeSpan ts=秒表。已用时间;
string elapsedTime=string.Format(“{0:00}:{1:00}:{2:00}.{3:00}”,
时,分,秒,
ts.毫秒/10);
Console.WriteLine(“运行时”+elapsedTime);
}
公共事务双重完成()
{
如果(aPi>0)
{
Msg=新建StringBuilder(“计算已成功完成”);
return aPi;//返回获取的值
}
其他的
{
返回0;//没有结果
}
}
公共无效点生成器(整数n,随机rnd)
{

对于(inti=1;i当你的整个并行部分都在锁的作用域内时,实际上没有什么是并行的。在任何给定的时刻,只有一个线程可以在锁的作用域内


您可以简单地使用不同的
随机
实例,而不是单个实例。

当您的整个并行部分位于锁定范围内时,实际上没有任何东西是并行的。在任何给定时刻,只有单个线程可以位于锁定范围内


您可以简单地使用不同的
随机
实例,而不是单个实例。

您编写的
PointGenerator
几乎无法从并行执行中获益

  • lock
    意味着它将基本上具有单线程性能,并增加线程开销
  • 全局状态
    N_0
    意味着您必须同步访问。当然,因为它只是一个int,所以您可以使用
    Interlocked
    类有效地递增它
我要做的是让每个
PointGenerator
都有一个不同的
Random
对象和一个不同的计数器。这样就不会有任何可能导致问题的共享可变状态。不过要小心,
Random
的默认构造函数使用系统的勾号计数。创建多个对象可能会导致随机错误具有相同种子的生成器

所有
PointGenerator
完成后,您将合并结果


这与and的一些TPL重载非常相似。

您编写了
PointGenerator
,它几乎无法从并行执行中获益

  • lock
    意味着它将基本上具有单线程性能,并增加线程开销
  • 全局状态
    N_0
    意味着您必须同步访问。当然,因为它只是一个int,所以您可以使用
    Interlocked
    类有效地递增它
我要做的是让每个
PointGenerator
都有一个不同的
Random
对象和一个不同的计数器。这样就不会有任何可能导致问题的共享可变状态。不过要小心,
Random
的默认构造函数使用系统的勾号计数。创建多个对象可能会导致随机错误具有相同种子的生成器

所有
PointGenerator
完成后,您将合并结果


这与和的一些TPL重载非常相似。

您应该避免
lock(randLock)
如果您有多处理器系统,多个程序可以并行执行,使用并行库可以在较短的时间内得到答案。在单处理器系统中,多个程序一个接一个地执行,因此执行永远不会加快,程序之间切换的开销会使执行变慢。您应该避免<代码>锁定(随机锁定)
如果您有多处理器系统,多个程序可以并行执行,使用并行库可以在较短的时间内得到答案。在单处理器系统中,多个程序一个接一个地执行,因此执行速度永远不会加快,程序之间切换的开销会使执行速度变慢。您可以做些什么同时创建多个
Random
s是基于时间创建一个,然后将其中的值用作其他值的种子:
var primarydrandom=new Random();var random1=new Random(primarydrandom.Next());var random2=new Random(primarydrandom.Next());…
。要同时创建多个
Random
s,可以根据时间创建一个,然后使用v
class TCalcPi//unparallel calculating method
    {
        int N;
        int N_0;
        double aPi;
        public StringBuilder Msg; // diagnostic message
        double x, y;
        Stopwatch stopWatch = new Stopwatch();

        public void Init(int aN)
        {
            stopWatch.Start();
            N = aN; // save total calculate-iterations amount
            aPi = -1; // flag, if no any calculate-iteration has been completed
            Msg = new StringBuilder("No any calculate-iteration has been completed");
        }
        public void Run()
        {
            if (N < 1)
            {
                Msg = new StringBuilder("Invalid N - value");
                return;
            }

            int i;
            Random rnd = new Random(); // to create randomizer
            for (i = 1; i <= N; i++)
            {
                x = rnd.NextDouble(); // to generate coordinates
                y = rnd.NextDouble(); // 
                if (((x -  0.5) * (x -  0.5) + (y -  0.5) * (y -  0.5)) <  0.25)
                {
                    N_0++; // coordinate in a circle! mark it by incrementing N_0
                }
            }
            aPi = 4.0 * ((double)N_0 / (double)N); // to calculate approximate Pi - value
            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
            Console.WriteLine("RunTime " + elapsedTime);
        }
        public double Done()
        {
            if (aPi > 0)
            {
                Msg = new StringBuilder("Calculates has been completed successful");
                return aPi; // return gotten value
            }
            else
            {
                return 0; // no result
            }
        }
    }