我有一段java代码(JDK 1.6.0._22,如果相关的话)
从那时起,性能有了很大的改进。我会尝试 Java 6 update 37 或 Java 7 update 10。
但它确实使用了大量内存
这可能意味着您访问数据的方式很重要。访问主内存中的数据可能比主缓存中的数据慢 20 倍以上。这意味着您必须保守地访问数据并充分利用您访问的每条新数据。
在 3 个线程之后,我可以将任意数量的线程放入任务中,但性能并没有提高
相反,我发现所有线程都在运行:只是非常慢。
这表明您正在最大限度地使用资源。考虑到您正在使用的内存量,最有可能被耗尽的资源是 cpu 到主内存的桥接器。我怀疑你有一个 64 线程的桥!这意味着您应该考虑可能使用更多 cpu 但改进访问内存的方式(减少随机性和增加顺序性)的方法,并在这样做时减少卷(尽可能使用更紧凑的类型)。例如我有“短小数点后两位”类型而不是浮点数,它可以使用一半的内存。
正如您所观察到的,当每个线程更新它自己的私有 AtomicLong 时,您将获得线性可扩展性。这根本不会使用CPU到主存的桥接。
来自@Marko
Peter,您知道这些多核架构如何与内存配合使用吗?
没有我想要的那么多,因为这个问题对于 Java 来说是不可见的。
每个核心都有独立的通道吗?
每个核心都有一个独立的主缓存通道。对于外部缓存,每个或 2-6 个缓存区域可能有一个通道,但在重负载下会出现大量冲突。
对于通往主存储器的桥梁,有一个非常宽的通道。这有利于长时间的顺序访问,但对于随机访问来说非常糟糕。单个线程可以通过随机读取来最大化这一点(足够随机,它们不适合外部缓存)
或者至少是独立的,只要不发生碰撞?
一旦耗尽主缓存(L1 通常为 32 KB),就会一直发生冲突。
因为否则缩放是一个大问题。
正如OP所示。大多数应用程序 a) 花费大量时间等待 IO b) 对小批量数据进行计算分配。对大量数据进行分配计算是最坏的情况。
我处理这个问题的方法是在内存中排列数据结构以进行顺序访问。我使用堆外内存,这很痛苦,但可以让您完全控制布局。 (我的源数据是内存映射以实现持久性)我通过顺序访问流式传输数据,并尝试充分利用这些数据(即,我最大限度地减少重复访问)即使使用 16 个内核,也很难假设所有这些都会被使用高效,因为我随时处理 40 GB 的源数据和大约 80 GB 的派生数据。
注意:高端 GPU 通过具有极高的内存带宽来解决此问题。高端处理器可达 250 GB/秒,而典型 CPU 约为 4-6 GB/秒。即便如此,它们更适合矢量化处理,并且它们引用的峰值性能可能很少有内存访问,例如曼德布罗特集。
http://www.nvidia.com/object/tesla-servers.html http://www.nvidia.com/object/tesla-servers.html