[英]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.