我一直试图深入了解这些概念是如何相关的。让我举一个简单的例子,解释一下思考,以便你能够纠正它。
假设我想尝试对两个数组进行排序
int[] A = { ... }; // very large, very unsorted
int[] B = { ... }; // very large, very unsorted
通过对它们进行排序“与我的系统并行,我可以对它们进行排序。”我利用Parallel.ForEach
做了很多东西的事实,我只是写了
var arrays = new List<int[]>(A, B);
Paralell.ForEach(arrays, (arr) => { Array.Sort(arr); });
现在让我说我在具有以下规范的机器上编译并运行它:
在案例1中,绝对不可能获得性能提升。它对A进行排序,然后对B进行排序,就像在常规foreach
循环中一样。
在第2种情况下,也没有性能提升,因为除非你有多个处理器,否则你的机器不能“一次做多于一件事。”即使它最终将它们排序不同的线程,控制线程的CPU做了一点A的排序,B的一点点排序,A的一点点等等,这不仅仅比排序所有A然后全部B更有效。
由于前一种情况中提到的原因,案例3是唯一可能获得性能提升的案例。
有人会批评我的理解吗?这是对还是错? (我没有计算机科学专业。所以请在曲线上给我评分。)
答案 0 :(得分:5)
在案例1中......它对A进行排序,然后对B进行排序
这不是线程的工作原理。操作系统快速上下文切换两个线程。在Windows上,默认情况下每秒发生64/3次。交错使得它看起来像A和B同时被排序。不容易观察到,调试器必须让你看看Array.Sort(),它不会。当然,速度不是很快,但放缓速度相当小。它是廉价的上下文切换,不需要重新加载页面映射表,因为线程属于同一个进程。您只需支付可能已删除的缓存,每3/64秒增加约5微秒(慢0.1%)很难准确测量。
在案例2中,......然后你的机器不能“一次做多于一件事”
可以,每个核心可以同时执行Sort()。主要是多核处理器。然而,它们必须共享单个资源,即内存总线。重要的是阵列的大小和RAM芯片的速度。大型阵列不适合处理器高速缓存,从技术上讲,存储器总线可能会被来自处理器内核的请求所饱和。在这种情况下没有帮助的是元素类型,比较两个int
值非常快,因为它只需要一条CPU指令。期望是x2加速,但如果你观察它需要更长时间,那么你就知道RAM是瓶颈。
案例3是唯一可能获得绩效增长的案例
不太可能。多处理器机器通常具有NUMA架构,为每个处理器提供自己的内存总线。它们之间的互连可用于将数据从一个总线转移到另一个总线。但是这样的处理器也具有多个核心。操作系统的工作就是弄清楚如何有效地使用它们。由于线程属于同一个进程,因此共享数据,它将强烈支持在同一处理器的内核上调度线程,并避免在互连上施加负载。所以期望它的表现与案例2相同。
这些是粗略的指导方针,您实际测量的现代机器设计要求。