java中的子进程非常昂贵。每个进程通常由多个线程支持。
- 一个线程来承载进程(通过Linux上的JDK 1.6)
- 一个线程来读取以读取/打印/忽略输入流
- 另一个线程来读取/打印/忽略错误流
- 更多线程来执行超时和监视并终止子进程由您的应用程序的
- 业务逻辑线程,保持直到子流程返回。
如果你有一个线程池子进程来执行任务,线程的数量就会失控。因此,峰值时可能有超过两倍的并发线程。
在很多情况下,我们fork一个进程只是因为没有人能够编写JNI来调用JDK中缺少的本机函数(例如chmod,ln,ls),触发shell脚本等。
有些线程可以被保存,但有些线程应该运行以防止最坏的情况(输入流上的缓冲区溢出)。
如何将Java中创建子进程的开销降至最低?
我正在考虑 NIO 流处理、组合和共享线程、降低后台线程优先级、重用进程。但我不知道它们是否可能。
Sub-process in java are very expensive. Each process is usually support by a NUMBERS of threads.
- a thread to host the process (by JDK 1.6 on linux)
- a thread to read to read/print/ignore the input stream
- another thread to read/print/ignore the error stream
- a more thread to do timeout and monitoring and kill sub-process by your application
- the business logic thread, holduntil for the sub-process return.
The number of thread get out of control if you have a pool of thread focking sub-process to do tasks. As a result, there may be more then a double of concurrent thread at peak.
In many cases, we fork a process just because nobody able to write JNI to call native function missing from the JDK (e.g. chmod, ln, ls), trigger a shell script, etc, etc.
Some thread can be saved, but some thread should run to prevent the worst case (buffer overrun on inputstream).
How can I reduce the overhead of creating sub-process in Java to the minimum?
I am thinking of NIO the stream handles, combine and share threads, lower background thread priority, re-use of process. But I have no idea are they possible or not.
发布评论
评论(7)
JDK7将解决这个问题并提供新的API redirectOutput/redirectError 重定向 stdout/stderr。
然而坏消息是他们忘记提供“Redirect.toNull”,这意味着你会想要做类似“if(*nix)/dev/null elsif(win)nil”的事情,
令人难以置信的是 NIO/2 api for Process 仍然丢失的;但我认为redirectOutput+NIO2的AsynchronizeChannel会有帮助。
JDK7 will address this issue and provide new API redirectOutput/redirectError in ProcessBuilder to redirect stdout/stderr.
However the bad news is that they forget to provide a "Redirect.toNull" what mean you will want to do something like "if(*nix)/dev/null elsif(win)nil"
Unbeliable that NIO/2 api for Process still missing; but I think redirectOutput+NIO2's AsynchronizeChannel will help.
我创建了一个开源库,允许 java 和子进程之间的非阻塞 I/O。该库提供了事件驱动的回调模型。它依赖于 JNA 库来使用特定于平台的本机 API,例如 Linux 上的 epoll、MacOS X 上的 kqueue/kevent 或 Windows 上的 IO Completion Ports。
该项目名为 NuProcess,可以在这里找到:
https://github.com/brettwooldridge/NuProcess
I have created an open source library that allows non-blocking I/O between java and your child processes. The library provides an event-driven callback model. It depends on the JNA library to use platform-specific native APIs, such as epoll on Linux, kqueue/kevent on MacOS X, or IO Completion Ports on Windows.
The project is called NuProcess and can be found here:
https://github.com/brettwooldridge/NuProcess
要回答您的主题(我不明白描述),我假设您的意思是 shell 子进程输出,请检查这些 SO 问题:
Java 的平台独立 /dev/null 输出接收器
Java 中是否存在 Null OutputStream?
或者您可以关闭 Unix 下正在执行的命令的 stdout 和 stderr:
To answer your topic (I don't understand description), I assume you mean shell subprocess output, check these SO issues:
platform-independent /dev/null output sink for Java
Is there a Null OutputStream in Java?
Or you can close stdout and stderr for the command being executed under Unix:
您不需要任何额外的线程来在 java 中运行子进程,尽管处理超时确实使事情变得有点复杂:
您也可以使用反射,如 是否可以从具有超时的输入流中读取? 获取 NIO
Process.getInputStream() 的 >FileChannel,但是您必须担心不同的 JDK 版本以换取摆脱轮询。
You don't need any extra threads to run a subprocess in java, although handling timeouts does complicate things a bit:
You could also play with reflection as in Is it possible to read from a InputStream with a timeout? to get a NIO
FileChannel
fromProcess.getInputStream()
, but then you'd have to worry about different JDK versions in exchange for getting rid of the polling.nio 不起作用,因为当您创建进程时,您只能访问 OutputStream,而不能访问 Channel。
您可以让 1 个线程读取多个 InputStream。
例如,
您可以将上述类与等待进程完成的另一个类配对,例如,
如果您使用 ProcessBuilder.redirectErrorStream(true),则不需要为每个错误流拥有 1 个线程,并且您不需要 1 个线程来读取进程输入流,如果您不向输入流写入任何内容,则可以简单地忽略该输入流。
nio won't work, since when you create a process you can only access the OutputStream, not a Channel.
You can have 1 thread read multiple InputStreams.
Something like,
You can pair the above class with another class that waits for the Processes to complete, something like,
As well, you don't need to have 1 thread for each error stream if you use ProcessBuilder.redirectErrorStream(true), and you don't need 1 thread for reading the process input stream, you can simply ignore the input stream if you are not writing anything to it.
既然您提到了 chmod、ln、ls 和 shell 脚本,听起来您正在尝试使用 Java 进行 shell 编程。如果是这样,您可能需要考虑使用更适合该任务的其他语言,例如 Python、Perl 或 Bash。虽然当然可以在 Java 中创建子进程,通过标准输入/输出/错误流等与它们交互,但我认为您会发现脚本语言使此类代码比 Java 更简洁且更易于维护。
Since you mention,
chmod
,ln
,ls
, and shell scripts, it sounds like you're trying to use Java for shell programming. If so, you might want to consider a different language that is better suited to that task such as Python, Perl, or Bash. Although it's certainly possible to create subprocesses in Java, interact with them via their standard input/output/error streams, etc., I think you will find a scripting language makes this kind of code less verbose and easier to maintain than Java.您是否考虑过使用用另一种语言(可能是 shell 脚本?)编写的单个长时间运行的帮助程序进程,该进程将通过 stdin 使用来自 java 的命令并执行文件操作作为响应?
Have you considered using a single long-running helper process written in another language (maybe a shell script?) that will consume commands from java via stdin and perform file operations in response?