Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.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# Invoke提供了最小的性能提升(如果有的话)_C#_.net_Performance_Task Parallel Library - Fatal编程技术网

C# Invoke提供了最小的性能提升(如果有的话)

C# Invoke提供了最小的性能提升(如果有的话),c#,.net,performance,task-parallel-library,C#,.net,Performance,Task Parallel Library,我编写了一个简单的控制台应用程序来测试Parallel.Invoke的性能,它基于Microsoft在msdn上的示例: public static void TestParallelInvokeSimple() { ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 1 }; // 1 to disable threads, -1 to enable them

我编写了一个简单的控制台应用程序来测试Parallel.Invoke的性能,它基于Microsoft在msdn上的示例:

public static void TestParallelInvokeSimple()
    {
        ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 1 }; // 1 to disable threads, -1 to enable them
        Parallel.Invoke(parallelOptions,
            () =>
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    Console.WriteLine("Begin first task...");
                    List<string> objects = new List<string>();
                    for (int i = 0; i < 10000000; i++)
                    {
                        if (objects.Count > 0)
                        {
                            string tempstr = string.Join("", objects.Last().Take(6).ToList());
                            objects.Add(tempstr + i);
                        }
                        else
                        {
                            objects.Add("START!");
                        }
                    }
                    sw.Stop();
                    Console.WriteLine("End first task... {0} seconds", sw.Elapsed.TotalSeconds);
                },
            () =>
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    Console.WriteLine("Begin second task...");
                    List<string> objects = new List<string>();
                    for (int i = 0; i < 10000000; i++)
                    {
                        objects.Add("abc" + i);
                    }
                    sw.Stop();
                    Console.WriteLine("End second task... {0} seconds", sw.Elapsed.TotalSeconds);
                },
            () =>
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    Console.WriteLine("Begin third task...");
                    List<string> objects = new List<string>();
                    for (int i = 0; i < 20000000; i++)
                    {
                        objects.Add("abc" + i);
                    }
                    sw.Stop();
                    Console.WriteLine("End third task... {0} seconds", sw.Elapsed.TotalSeconds);
                }
            );
    }
当我通过将MaxDegreeOfParallelism设置为-1来启用线程时,我得到:

Begin third task...
Begin first task...
Begin second task...
End second task... 5.9112167 seconds
End third task... 13.113622 seconds
End first task... 19.5815043 seconds
done!
Total elapsed time: 19.5884057 seconds
这实际上与顺序处理的速度相同。由于任务1花费的时间最长,大约为10秒,因此我预计线程总共需要大约10秒来运行所有3个任务。那么是什么原因呢为什么是并行的。调用“单独运行我的任务”的速度较慢,但并行运行?

顺便说一句,我在一个实际的应用程序中使用Parallel.Invoke同时执行许多不同的任务(其中大部分是运行查询)时看到了完全相同的结果


如果你认为是我的电脑,再想想。。。它已经有1年的历史了,拥有8GB内存、windows 8.1、Intel Core I7 2.7GHz 8核cpu。当我一遍又一遍地运行测试时,我的电脑并没有过载。我的电脑从未达到最大值,但在运行时明显显示cpu和内存增加。

我没有对此进行分析,但这里的大部分时间可能都花在为这些列表和小字符串分配内存上。这些“任务”实际上除了用最少的输入和几乎没有处理时间来增加列表之外,什么都没有做

认为:

objects.Add("abc" + i);
本质上只是创建一个新字符串,然后将其添加到列表中。创建这样的小字符串在很大程度上只是一个内存分配练习,因为字符串存储在堆上。此外,为
列表
分配的内存将很快填满—每次这样做时,列表都会为自己的存储重新分配更多内存


现在,堆分配在一个进程内序列化-一个进程内的四个线程不能同时分配内存。内存分配请求是按顺序处理的,因为共享堆与任何其他需要防止并发破坏的共享资源一样

因此,您有三个非常需要内存的线程,它们可能会花费大部分时间等待彼此完成获取新内存


用CPU密集型工作(例如:做一些数学等)填充这些方法,您将看到结果非常不同。教训是,并非所有任务都是有效并行的,也并非所有任务都是以您可能认为的方式进行的。例如,可以通过在自己的进程中运行每个任务来加速上述过程——例如,使用自己的私有内存空间,就不会有内存分配争用

我没有对此进行分析,但这里的大部分时间可能都花在为这些列表和小字符串分配内存上。这些“任务”实际上除了用最少的输入和几乎没有处理时间来增加列表之外,什么都没有做

认为:

objects.Add("abc" + i);
本质上只是创建一个新字符串,然后将其添加到列表中。创建这样的小字符串在很大程度上只是一个内存分配练习,因为字符串存储在堆上。此外,为
列表
分配的内存将很快填满—每次这样做时,列表都会为自己的存储重新分配更多内存


现在,堆分配在一个进程内序列化-一个进程内的四个线程不能同时分配内存。内存分配请求是按顺序处理的,因为共享堆与任何其他需要防止并发破坏的共享资源一样

因此,您有三个非常需要内存的线程,它们可能会花费大部分时间等待彼此完成获取新内存


用CPU密集型工作(例如:做一些数学等)填充这些方法,您将看到结果非常不同。教训是,并非所有任务都是有效并行的,也并非所有任务都是以您可能认为的方式进行的。例如,可以通过在自己的进程中运行每个任务来加速上述过程——例如,使用自己的私有内存空间,就不会有内存分配争用

字符串是一种“特殊”类型。如果您使用其他数据类型会发生什么?您正在进行大量内存分配。实际上,您的代码不是CPU绑定的,而是内存和GC绑定的。由于.NET中的垃圾收集器将强制所有线程在执行其操作之前冻结,因此您已设法将代码限制在单个线程所能提供的范围内。甚至除了GC,您所做的大部分工作都是分配。这给内存带来了很大的压力,而对CPU的压力很小。内存访问速度很慢,而且非常不可并行(即在台式PC中)。@Luaan-你说得对,GC加上分配大量堆内存会降低性能。我刚刚发现了一篇相关文章:字符串是一种“特殊”类型。如果您使用其他数据类型会发生什么?您正在进行大量内存分配。实际上,您的代码不是CPU绑定的,而是内存和GC绑定的。由于.NET中的垃圾收集器将强制所有线程在执行其操作之前冻结,因此您已设法将代码限制在单个线程所能提供的范围内。甚至除了GC,您所做的大部分工作都是分配。这给内存带来了很大的压力,而对CPU的压力很小。内存访问速度很慢,而且非常不可并行(即在台式PC中)。@Luaan-你说得对,GC加上分配大量堆内存会降低性能。我刚刚发现了一篇相关文章:“堆分配在一个进程内序列化”——我不知道!这正是问题所在。我将代码更改为使用数学库中的一些函数,并且不分配任何内存,现在是并行的。谢谢你的解释。@goku_da_大师注意,在.N中有一些不同的地面军事系统