2013-06-25 77 views
8

當一個Java程序調用System.out.println()或者一個Scala程序調用println()做線程塊嗎?控制檯是否輸出阻止操作?

我正在寫一個Scala程序,其中包含大量的子任務。每個子任務都在Future中執行。建議演員和期貨內部的代碼不要阻塞,以便後續任務不必等待。但是我想在控制檯上進行非常多的打印。

如果是阻塞操作:我可以做些什麼來優化性能?

  • 我是否應該使用專用線程進行控制檯輸出,以便線程是唯一阻止的線程?
  • 其他建議?

當然我可以嘗試在StringBuilder中減少輸出量或收集一些輸出並將它一起打印在一起,這樣可以減少輸出操作的次數。

回答

12

當一個Java程序調用System.out.println()或一個Scala程序調用println()時,線程塊會被阻塞嗎?

是和否。 System.out是一個PrintStream這是一個同步類。因此寫入大量System.out的多個線程肯定會相互阻塞。但是,一旦線程獲得鎖定,IO是否會阻塞該線程取決於體系結構。如果你編寫大量的IO來壓倒底層硬件的容量,那麼寫入將會得到塊。此外,做很多小寫(而不是緩衝),也會減慢線程的速度。

我是否應該使用專用的線程進行控制檯輸出,以便線程是唯一阻止的線程?

好主意,是的。然後這個線程可以通過一個BufferedWriter或某種類型的log4j或其他日誌包寫入,與System.out相比,性能會更高。您需要使用類似於BlockingQueue的東西來排隊同步的消息,但IO不會阻塞此隊列,除非您的消息生成速度快於IO通道可以持續消息的速度。

當然,我可以嘗試減少輸出量或在StringBuilder中收集某些輸出並將其一起打印在一起,從而減少輸出操作的次數。

BufferedWriter會照顧你。

其他的意見?

  • 如前所述,使用更好的日誌記錄程序包或單線程寫入程序。
  • 將日誌寫入具有更多IO帶寬的不同物理磁盤。
  • 切換到內存文件系統或硬件以增加IO帶寬。 SSD ++。
  • 通過網絡將它發送到另一個盒子來做實際的持續關閉盒子。使用GzipOutputStream來實時壓縮它。
+0

*日誌寫入到不同的文件系統。*你的意思是不同的物理驅動器?或者如果你的意思是說一個文件系統比另一個文件系統更適合這樣的任務(例如ext *和btrfs),你能否透露這些名字? –

+0

不,我的意思是IO鏈,而不是不同的FS類型@ om-nom-nom。偉大的用戶名稱btw。 :-) – Gray

+0

這個。這是一個格式良好且有用的答案。 – Andy

4

它取決於。在Windows操作系統這是一個阻止操作,並涉及到很多內核的東西打印到控制檯的東西。在UNIX-OS中,操作被緩衝,所以它不被認爲是慢的。

我建議你去緩衝的方法,並有一個單獨的線程也是一個好主意。或者,如果你的輸出不重要,你可以將它寫入一個文件,這比寫入控制檯要快得多。

+0

還記得System.out的不一定打印到控制檯(它可能已被重定向到一個文件「命令> out.txt」) – faffaffaff