Process阻塞问题

Java中

Runtime.getInstance().exec (String cmd)

或者

new ProcessBuilder(String cmd).start()

都可以产生子进程对象Process。通过调用Process对象的waitFor()方法可以使主进程进入等待状态,直至子进程执行完毕,再进行下一步工作。如果对子进程处理不当,有可能造成主进程阻塞,整个程序死掉。

java Api中关于Process说的是:

ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获取相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。

创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream()getInputStream()getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。

在对getOutputStream()getInputStream()getErrorStream()的描述中,有个注意事项:对其输出流和错误流进行缓冲是一个好主意!嗯,好抽象啊!

问题正在于此,Process.getInputStream()和Process.getErrorStream()分别返回Process的标准输出流和错误流,两个流如果处理不当,其缓冲区不能被及时清除而被塞满,则进程被阻塞,即使调用Process.destory()也未必能销毁被阻塞的子进程。


如果尝试同步获取Process的输出流和错误流进行处理,未必有效,顺序执行过程中,输出流和错误流常常不能得到及时处理。解决方案有两个。


方案一:并发获取Process的输出流和错误流。

通过启动两个线程来并发地读取和处理输出流和错误流,懒得打开IDE了,就大概敲一下代码吧,可能有错误,如下:

调用者:

class ProcessExecutor
{
	private Process p;
	private List<String> outputList;
	private List<String> errorOutputList;
	public ProcessExecutor(Process p) throws IOException
	{
		if(null == p)
		{
			throw new IOException("the provided Process is null");
		}
		this. p = p;
	}
	public List<String> getOutputList()
	{
		return this. outputList;
	}
	public List<String> getErrorOutputList()
	{
		return this.errorOutputList;
	}
	public int execute()
	{
		int rs = 0;
		Thread outputThread = new ProcessOutputThread(this.p.getInputStream());
		Thread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream());
		outputThread.start();
		errorOutputThread.start();
		rs = p.waitFor();
		outputThread.join();
		errorOutputThread.join();
		this.outputList = outputThread.getOutputList();
		this.errorOutputList = errorOutputThread.getOutputList();
		return rs;
	}
}


流处理线程

class ProcessOutputThread extends Thread
{
	private InputStream is;
	private List<String> outputList;
	public ProcessOutputThread(InputStream is) throws IOException
	{
		if(null == is)
		{
			throw new IOException("the provided InputStream is null");
		}
		this. is = is;
		this.outputList = new ArrayList<String>();
	}
	public List<String> getOutputList()
	{
		return this. outputList;
	}
	@Override
	public void run()
	{
		InputStreamReader ir = null;
		BufferedReader br = null;
		try
		{
			ir = new InputStreamReader(this.is);
			br = new BufferedReader(ir);
			String output = null;
			while(null != (output = br.readLine()))
			{
				print(output);
				this.outputList.add(output);
			}
		}
		catch(IOException e)
		{
			e.print();
		}
		finally
		(
			try
			{
				if(null != br)
				{
					br.close();
				}
				if(null != ir)
				{
					ir.close();
				}
				if(null != this.is)
				{
					this.is.close();
				}
			}
			catch(IOException e)
			{
				e.print();
			}
		)
	}
}


方案二:用ProcessBuilder的redirectErrorStream()方法合并输出流和错误流。

public int execute()
{
	int rs = 0;
	String[] cmds = {...};//command and arg  
	ProcessBuilder builder = new ProcessBuilder(cmds);  
	builder.redirectErrorStream(true);  
	Process process = builder.start();  
	BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));  
	String output = null;  
	while (null != (readLine = br.readLine()))
	{  
   		print(output);   
	}  
	rs = process.waitFor();
	return rs;
} 


<think> 首先,用户的问题是:“我想了解process start操作是阻塞还是非阻塞 请问process start操作是阻塞还是非阻塞”。用户指的是Python中的Process start操作,可能来自multiprocessing模块。 从引用中,我可以看到相关的内容: - 引用[3]提到了Process的使用:`p_obj1 = Process(target=task, args=('jason_sb', ))``p_obj1.start()`,其中start方法是用来启动子进程的。 - 引用[3]还说:`p_obj1.start() # 告诉操作系统,去创建一个子进程`,然后提到`join()`方法等待子进程结束。 关键是要确定start操作本身是阻塞还是非阻塞。回想一下阻塞阻塞的定义: - 引用[2]定义阻塞操作是指在等待过程中阻塞当前线程,直到操作完成;非阻塞操作立即返回,不阻塞当前线程。 - 引用[1]讨论了Python中的线程阻塞问题,但用户的问题是关于进程的start操作。 在Python的multiprocessing模块中: - `Process.start()`方法是非阻塞的。它启动子进程并立即返回,允许主进程继续执行其他任务。 - 之后,你可以使用`join()`方法等待子进程完成,这会阻塞当前线程直到子进程结束。 从引用[3]的代码示例中: - 它多次调用`start()`并紧跟`join()`,但`start()`本身是异步的。 - 代码中:`p_obj1.start()`后立即`p_obj1.join()`,但这并不意味着start是阻塞的;start启动进程,join等待结束。 在引用[5]中,提到multiprocessing.Pool,但同样适用于Process:start是非阻塞的。 我的回答需要: - 使用中文。 - 结构清晰,逐步解释。 - 确保内容真实可靠。 - 遵循系统指令:行内数学用$...$,独立公式用$$...$$(但这里可能不需要数学)。 - 生成相关问题。 - 在引用末尾添加引用标识。 回答结构: 1. 直接回答用户的提问:Process start操作是非阻塞的。 2. 解释为什么是非阻塞的:它立即返回,操作系统异步创建子进程。 3. 对比阻塞操作:例如,join是阻塞的。 4. 提供代码示例来演示。 5. 引用相关段落来支持。 6. 生成相关问题。 引用支持: - 引用[3]:展示了start的使用,暗示它是非阻塞的,因为启动后主进程可以继续。 - 在其他引用中,没有直接说start是非阻塞的,但可以从上下文中推断。 最终回答: - 声明:在Python的multiprocessing模块中,`Process.start()`方法是非阻塞的。 - 解释:调用start()后,它会异步启动新进程,并立即返回控制权给调用者(主进程)。 - 示例:显示一个简单代码,其中start后立即做其他事。 - 注意事项:尽管start是非阻塞的,但你可能需要使用join()来等待子进程完成,以避免主进程过早退出。 - 生成相关问题。 相关问题: 1. 如何等待子进程完成? 2. Python中多进程与多线程的区别? 3. 阻塞阻塞操作在并发编程中的应用? </think> ### Process start操作是阻塞还是非阻塞? 在Python的`multiprocessing`模块中,`Process.start()`方法是**非阻塞操作**。下面我将逐步解释原因、行为机制相关注意事项,确保内容清晰可靠。 #### 1. **`Process.start()`的行为机制** - `Process.start()`用于启动一个新进程(子进程)。 - **非阻塞特性**:调用`start()`时,它会立即返回控制权给主进程(调用线程),而不会等待子进程实际启动或运行完成。操作系统在后台异步创建子进程,主进程可以继续执行后续代码[^3][^5]。 - 例如: ```python from multiprocessing import Process import time def task(name): print(f"子进程 {name} 启动") time.sleep(2) print(f"子进程 {name} 结束") if __name__ == '__main__': p = Process(target=task, args=('test',)) p.start() # 非阻塞:立即返回,主进程继续运行 print("主进程继续执行...") p.join() # 阻塞:等待子进程结束 ``` 输出可能为: ``` 主进程继续执行... 子进程 test 启动 子进程 test 结束 ``` 这里,`start()`后主进程立即打印消息,证明其非阻塞。 #### 2. **与阻塞操作的对比** - **阻塞操作**:如`Process.join()`或文件读取`read_file()`,会挂起当前线程直到操作完成,期间无法执行其他任务[^2][^4]。 - 例如:`p.join()`会阻塞主进程,直到子进程终止。 - **非阻塞操作的优点**:允许主进程在子进程运行期间并发执行其他任务,提高资源利用率,尤其适用于IO密集型或CPU密集型计算[^1][^5]。 #### 3. **关键注意事项** - **子进程启动延迟**:虽然`start()`非阻塞,但操作系统可能需要时间初始化子进程。实际启动可能稍有延迟(毫秒级)。 - **资源管理**:过度启动进程可能导致资源竞争。建议使用`Pool`管理进程数上限[^5]。 - **同步需求**:若主进程需要子进程的结果,必须在`start()`后调用`join()`或同步机制(如队列),否则主进程可能提前退出导致子进程中断[^3]。 #### 4. **为什么是非阻塞?底层原理** - `start()`通过系统调用(如Unix的`fork()`)请求操作系统创建新进程。操作系统将此请求加入调度队列,并立即返回状态给Python解释器,不等待进程实际启动。 - 这符合通用编程模型:进程创建是异步操作,避免浪费CPU周期在等待上[^3][^5]。 #### 5. **引用总结** - `start()`的非阻塞特性使其适合构建高并发应用,如Web服务器处理多个请求[^4]。 - 在Python中,多进程(`multiprocessing`)可绕过GIL限制,实现真正的并行计算,而`start()`是实现并发的关键一步[^1][^5]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值