Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 并行。调用工作缓慢_C#_Parallel Processing_Task - Fatal编程技术网

C# 并行。调用工作缓慢

C# 并行。调用工作缓慢,c#,parallel-processing,task,C#,Parallel Processing,Task,为了比较性能,我编写了Methode#1和Methode#2代码。方法1使用construnction for,方法2使用Parallel.Invoke。在第二种情况下,工作非常缓慢。我不明白为什么会这样 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using S

为了比较性能,我编写了Methode#1和Methode#2代码。方法1使用construnction for,方法2使用Parallel.Invoke。在第二种情况下,工作非常缓慢。我不明白为什么会这样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using Mpir.NET;
using System.Runtime.Serialization;
using System.Diagnostics;

namespace ConsoleApplication4
{
    class Program
    {
        public class numbers
        {
            public numbers(mpz_t p, mpz_t q)
            {
                this.q = q;
                this.p = p;
            }
            mpz_t q;
            mpz_t p;
        };

        static void Main(string[] args)
        {
            Int32 arraySize = 400;
            ConcurrentBag<numbers> pairsCB = new ConcurrentBag<numbers>();
            ConcurrentBag<Action> cbTasks = new ConcurrentBag<Action>();
            HashSet<numbers> uniqueCB = new HashSet<numbers>(pairsCB.ToArray());

            mpz_t[] numbersArray = new mpz_t[arraySize];

            for (Int32 i = 0; i < arraySize; i++)
            {
                numbersArray[i] = i*i+i+1; 
            }


            //Methode #1 
            Stopwatch stopwatch1 = new Stopwatch();
            stopwatch1.Start();

            for (Int32 j = 0; j < arraySize; j++)
            {
                checkDivisible(numbersArray[j], pairsCB);
            }

            uniqueCB = new HashSet<numbers>(pairsCB.ToArray());
            stopwatch1.Stop();
            Console.WriteLine("Methode Count Unique Pairs  Count:{0}\tTime elapsed:{1}", uniqueCB.Count(), stopwatch1.Elapsed);

            //Methode #2 
            Stopwatch stopwatch2 = new Stopwatch();
            stopwatch2.Start();
            pairsCB = new ConcurrentBag<numbers>();

            for(Int32 j = 0; j < arraySize; j++)
            {
                mpz_t value = numbersArray[j];
                cbTasks.Add(new Action(() => checkDivisible(value, pairsCB)));
            }

            Action[] tasks =  cbTasks.ToArray();

            Parallel.Invoke(tasks);

            stopwatch2.Stop();
            Console.WriteLine("Methode Count Unique Pairs  Count:{0}\tTime elapsed:{1}", uniqueCB.Count(), stopwatch2.Elapsed);


            Console.ReadKey();
        }

        private static void checkDivisible(mpz_t n, ConcurrentBag<numbers>  pq)
        {
            mpz_t p = 1; 
            mpz_t q = 1;    

            for (Int32 i = 2; i < n; i++)
            {
                if (n % i == 0)
                {
                    q = i;
                    p = n / i;
                    pq.Add(new numbers(p, q));
                }
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用System.Collections.Concurrent;
使用Mpir.NET;
使用System.Runtime.Serialization;
使用系统诊断;
命名空间控制台应用程序4
{
班级计划
{
公共课号
{
公共号码(mpz_t p、mpz_t q)
{
这个。q=q;
这个,p=p;
}
mpz_t q;
mpz_t p;
};
静态void Main(字符串[]参数)
{
Int32 arraySize=400;
ConcurrentBag pairsCB=新ConcurrentBag();
ConcurrentBag cbTasks=新ConcurrentBag();
HashSet uniqueCB=新的HashSet(pairsCB.ToArray());
mpz_t[]numbersArray=新的mpz_t[arraySize];
对于(Int32 i=0;icheckDivisible(value,pairsCB));
}
Action[]tasks=cbTasks.ToArray();
并行调用(任务);
秒表2.Stop();
WriteLine(“Methode Count Unique Pairs Count:{0}\t运行时间:{1}”、uniqueCB.Count()、stopwatch2.appeased);
Console.ReadKey();
}
私有静态无效校验可分(mpz_t n,ConcurrentBag pq)
{
mpz_t p=1;
mpz_t q=1;
对于(Int32 i=2;i
您可以使用的备选方案:

//Methode #2 
Stopwatch stopwatch2 = new Stopwatch();
stopwatch2.Start();
pairsCB = new ConcurrentBag<numbers>();

Parallel.For(0, arraySize, (index) => 
{
     checkDivisible(numbersArray[index], pairsCB);
});

stopwatch2.Stop();

第二种方法较慢的原因有很多

  • checkDivisible
    没有做足够的工作来证明并行化的合理性。并行化和同步的开销可能大于任何好处
  • ConcurrentBag是一个特殊用途的集合,它将数据存储在线程本地存储中,确保线程可以快速访问它编写的项目。它实际上比其他场景中的其他并发集合慢
  • checkDivisible
    的所有调用都写入同一个集合,这成为一个热点。最好从每次调用中返回一个简单数组,并在最后一步合并所有数组
  • 并发调用太多。Invoke必须单独安排每个操作<代码>并行。另一方面,For或
    并行。ForEach
    知道所有调用都是相同的,因此它们可以根据处理器的数量对数据进行分区,确保并行开销最小
  • 第一步是修改
    checkDivisible

        private static List<number> checkDivisible(mpz_t n)
        {
            mpz_t p = 1; 
            mpz_t q = 1;    
    
            List<number> nums=new List<numbers>();
    
            for (Int32 i = 2; i < n; i++)
            {
                if (n % i == 0)
                {
                    q = i;
                    p = n / i;
                    nums.Add(new numbers(p, q));
                }
            }
            return numbers;
        }
    
    你可以写:

    var results= (from n in numbersArray.AsParallel()
                 from number in checkDivisible(n)
                 select n).ToList();
    

    与Parallel一样。例如,PLINQ将根据机器上的内核数对
    numbersArray
    中的数据进行分区,并行处理这些分区,最后将它们合并到一个列表中。

    这只是因为这种方法非常小,而且创建线程的开销很大。只有当您有很长的进程(文件访问、下载、大量计算等)时才使用并行性。如果任务不能持续至少0.1秒,那么并行化它是没有用的。安排时间比运行时间要多。ConcurrentBag不是通用集合,它用于在本地存储写入它的每个线程的数据。在任何情况下,由于您使用的是parelle.Invoke,因此任务根本不需要并发集合。使用ConcurrentQueue获取数字。更好的方法是,通过从每次调用中返回一个
    numbers
    数组并在最后合并它们来避免完全使用公共集合-这本质上是任何map/reduce算法panagiotis Kanavos中的
    reduce
    步骤-您能提供优化的代码吗?我不知道如何并行返回数组。调用并合并数据。我想使用Parallel.Invoke来理解它是如何工作的。@YuriyTigiev,正如您从评论和其他答案中看到的,在这种情况下,这不会带来任何好处。如果你有更大的计算要运行,它可能已经运行了。@YuriyTigiev在这种情况下调用这个方法是错误的(并行处理大量数据),它显示在基准测试中。对源数据进行分区很重要,这是并行的。Invoke在实际程序中不起作用的。我会在checkDivisible中使用大量计算。@YuriyTigiev Parallel.For可能会更快,尽管。。。我会对它进行测试并运行一个基准测试,以确保…@YuriyTigiev更愿意更新您的问题或添加注释请您为Parallel.Invoke提供正确的代码。我理解Parallel.For更好,但我希望用户Parallel.Invoke@YuriyTigiev为什么?你想解决什么问题?为每个数字运行一个单独的任务是错误的,但调用就是这样做的。您必须重写并行的
    Forvar results=new ConcurrentQueue<IList<numbers>>();
    
    Parallel.For(0, arraySize, (index) => 
    {
         var local=checkDivisible(numbersArray[index]);
         results.Add(local);
    });
    
    var final=results.SelectMany(r=>r).ToList();
    
        private static IEnumerable<number> checkDivisible(mpz_t n)
        {
            mpz_t p = 1; 
            mpz_t q = 1;    
    
            for (Int32 i = 2; i < n; i++)
            {
                if (n % i == 0)
                {
                    q = i;
                    p = n / i;
                    yield return new numbers(p, q);
                }
            }
        }
    
    var results= (from n in numbersArray.AsParallel()
                 from number in checkDivisible(n)
                 select n).ToList();