繁体   English   中英

对Java在多处理期间如何共享变量感到困惑

[英]Confused on how Java shares variables during multiprocessing

我刚刚开始使用Java,因此很抱歉,如果这个问题的答案很明显。 我真的不知道如何在Java中共享变量。 我一直在玩python,想尝试将一些代码移植到Java上以更好地学习语言。 我的代码很多,但是我不确定在Java中变量的多处理和共享是如何工作的(我的进程没有磁盘绑定,并且使用很多cpu和列表搜索)。

在Python中,我可以这样做:

from multiprocessing import Pool, Manager
manager = Manager()
shared_list = manager.list()
pool = Pool(process=4) 
for variables_to_send in list_of_data_to_process:
       pool.apply_async(function_or_class, (variables_to_send, shared_list))
pool.close()
pool.join()

我在弄清楚如何在Java中像这样进行多处理和共享时遇到了一些麻烦。 这个问题帮助我(通过代码)了解了如何实现runnable可以提供帮助,并且我开始认为Java可能会自动对多线程进行处理(如果我错了,请更正我,我读到一旦线程超出了CPU的容量,它们被转移到另一个CPU?甲骨文文档似乎更关注线程而不是多处理)。 但这并未说明如何在过程之间共享列表或其他变量(并使它们保持足够接近的同步)。

有什么建议或资源吗? 我希望我正在寻找错误的东西(java多处理),并且希望它与我上面的代码一样简单(或类似简单)。

谢谢!

线程和进程之间有一个重要的区别,您现在正在运行它:除了某些例外, 线程共享内存,而进程不共享内存

请注意,真正的操作系统几乎可以满足我要说的一切,但是在典型情况下并没有使用这些功能。 因此,要启动一个新进程,必须使用系统调用(在* nix上,这是fork() )以某种方式克隆当前进程,然后替换其中的代码,堆栈,命令行参数等。子进程与另一个系统调用(在* nix上,这是exec()系列系统调用)。 Windows具有这两个系统调用的大致等效项,因此我要说的都是跨平台的。 而且,Java运行时环境在幕后负责所有这些系统调用,没有JNI或其他互操作技术,您将无法真正执行它们。

关于此模型,有两点需要注意:子进程不共享父进程的地址空间,并且子进程的整个地址空间在exec()调用中被替换。 因此,父进程中的变量对子进程不可用,反之亦然。

线程模型完全不同。 线程有点像精简进程,因为每个线程都有自己的指令指针,并且(在大多数系统上)线程是由操作系统调度程序调度的。 但是,线程是进程的一部分。 每个进程至少有一个线程,并且进程中的所有线程共享内存。

现在解决您的问题:

如代码示例所示,Python的多处理模块只需很少的努力即可生成进程。 在Java中,产生一个新进程需要更多的工作。 它涉及使用ProcessBuilder.start()Runtime.exec()创建一个新的Process对象。 然后,您可以将字符串传递给子进程,获取其输出,等待其退出,以及其他一些通信原语。 我建议编写一个程序来充当协调器并启动每个子进程,并编写一个与您的示例中的function_or_class大致对应的工作程序。 协调器可以打开工作程序的多个副本,为每个任务分配一个任务,然后等待所有工作程序完成。

您可以为此目的使用Java线程。 您需要创建一个用户定义的类。 该类应该具有setter方法,通过该方法可以设置shared_list对象。 在Run()方法中实现Runnable接口并执行处理任务。 您可以在互联网上找到很好的例子。 如果共享相同的shared_list实例,则需要确保对该变量的访问已同步。

这不是在Java中使用线程的最简单方法,但是对您发布的python代码不开放。 任务类是可调用接口的实例,并且具有调用方法。 当我们创建10000个Task实例中的每个实例时,我们将它们传递给同一列表的引用。 因此,当所有这些对象的调用方法都被调用时,它们将使用相同的列表。

我们在这里使用4个线程的固定大小的线程池,因此我们提交的所有任务都将排队,并等待一个线程可用。

public class SharedListRunner {
    public void RunList() {
        ExecutorService executerService = Executors.newFixedThreadPool(4);
        List<String> sharedList = new List<String>();
        sharedList.add("Hello");
        for(int i=0; i < 10000; i++)
            executerService.submit(new Task(list));
    }
}

public class Task implements Callable<String> {

    List<String> sharedList;    

    public Task(List<String> sharedList) {
            this.sharedList = sharedList;
    }

    @Override
    public String call() throws Exception {
            //Do something to shared list
            sharedList.size();  
            return "World";
    }
}

任何时候都有4个线程正在访问该列表。 如果要进一步挖掘访问该列表的4个Java线程,则可能有更少的OS线程为这4个Java线程提供服务,并且甚至更少的处理器线程通常每个cpu内核为2或4。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM