10

我正在研究一种科学应用程序,该应用程序具有可以并行进行的易于分离的部分。因此,我将这些部分编写为每个独立线程运行,尽管这似乎不是将事物分成线程的标准原因(即,不阻塞某些退出命令等)。

几个问题:

这是否真的为我在标准多核桌面上买了任何东西 - 即,如果我有一个当前的 JVM,线程实际上会在单独的核心上运行,还是我必须做其他事情?

我几乎没有所有线程都读取(尽管从未写入)的对象。潜在的问题?这些问题的解决方案?

对于实际的集群,您能否推荐将线程分发到各个节点的框架,这样我就不必自己管理(好吧,如果存在的话)?澄清:我的意思是自动将线程转换为单个节点的任务或使整个集群看起来像单个 JVM(即,它可以将线程发送到它可以访问的任何处理器)或其他任何东西。基本上,在集群上以一种有用的方式实现并行化,因为我已经将它构建到算法中,并且我的工作量很少。

奖励:大部分评估由集合比较(例如,并集、交集、包含)和一些键映射组成,以获得相关集合。我在 FORTRAN、C 和 C++ 方面的经验有限(第一个学期是科学计算学期,另外两个学期是 10 年前的 HS AP 课程)——如果我将我的用其中一种语言从 Java 前端到算法后端,我的经验水平会发现用这些语言实现这些操作会带来什么样的头痛?

4

3 回答 3

8
  • 是的,使用独立线程将在普通 JVM 中使用多个内核,而无需您做任何工作。

  • 如果仅读取任何内容,则可以由多个线程读取。如果您可以使有问题的对象不可变(以保证它们永远不会被更改)那就更好了

  • 我不确定您正在考虑哪种集群,但您可能想查看Hadoop。请注意,分布式计算分配任务而不是线程(通常,无论如何)。

于 2009-10-07T17:05:10.103 回答
5

多核使用

Java 运行时通常安排线程在所有可用的处理器和内核上同时运行。我认为可以限制这一点,但这需要额外的工作;默认情况下,没有限制。

不可变对象

对于只读对象,将其成员字段声明为final,这将确保在创建对象时分配它们并且永远不会更改。如果一个字段不是final,即使它在构造后从未更改过,在多线程程序中也可能存在一些“可见性”问题。这可能导致一个线程所做的分配永远不会对另一个线程可见。

任何被多个线程访问的可变字段都应该被声明volatile,被同步保护,或者使用一些其他的并发机制来确保线程间的变化是一致的和可见的。

分布式计算

在 Java 中用于这种性质的分布式处理的最广泛使用的框架称为Hadoop。它使用称为map-reduce 的范例。

本机代码集成

与其他语言集成不太值得。由于其自适应字节码到本机编译器,Java 在广泛的计算任务上已经非常快。在没有实际测试的情况下假设另一种语言更快是错误的。此外,使用 JNI 与“本机”代码集成非常繁琐、容易出错且复杂;使用像 JNA 这样更简单的接口非常慢,并且会很快消除任何性能提升。

于 2009-10-07T17:21:31.753 回答
1

正如一些人所说,答案是:

  1. 核心上的线程 - 是的。Java 长期以来一直支持本机线程。大多数操作系统都提供了内核线程,这些线程会自动安排到您拥有的任何 CPU 上(实现性能可能因操作系统而异)。

  2. 简单的答案是它通常是安全的。更复杂的答案是您必须确保在任何线程可以访问它之前实际创建和初始化您的对象。这可以通过以下两种方式之一解决:

    • 让类加载器使用单例(和延迟类加载)为您解决问题:

      public class MyImmutableObject
      {
          private static class MyImmutableObjectInstance {
              private static final MyImmutableObject instance = new MyImmutableObject();
          }
          public MyImmutableObject getInstance() {
              return MyImmutableObjectInstance.instance;
          }
      }
      
    • 显式使用获取/释放语义来确保一致的内存模型:

      MyImmutableObject foo = null;
      volatile bool objectReady = false;
      
      // initializer thread:
      ....
      /// create & initialize object for use by multiple threads
      foo = new MyImmutableObject();
      foo.initialize();
      
      // release barrier
      objectReady = true;
      
      // start worker threads
      public void run() {
         // acquire barrier
         if (!objectReady)
             throw new IllegalStateException("Memory model violation");
      
         // start using immutable object foo
      }
      

    我不记得如何利用 Java 的内存模型来执行后一种情况。我相信,如果我没记错的话,对 volatile 变量的写入相当于释放屏障,而从 volatile 变量读取相当于获取屏障。此外,使布尔值 volatile 与对象相反的原因是,由于内存模型的限制,对 volatile 变量的访问成本更高 - 因此,布尔值允许您强制执行内存模型,然后可以完成对象访问线程内更快。

  3. 如前所述,有各种各样的 RPC 机制。还有 RMI,它是一种在远程目标上运行代码的本机方法。还有像 Hadoop 这样的框架,它提供了一个更完整的解决方案,可能更合适。

  4. 对于调用本机代码,它非常难看——Sun 确实不鼓励使用 JNI,因为它使 JNI 变得丑陋而复杂,但这是可能的。我知道至少有一个商业 Java 框架可以加载和执行本机动态库,而无需担心 JNI(不确定是否有任何免费或 OSS 项目)。

祝你好运。

于 2009-10-07T17:40:29.423 回答