Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non blocking subprocess.call

I'm trying to make a non blocking subprocess call to run a slave.py script from my main.py program. I need to pass args from main.py to slave.py once when it(slave.py) is first started via subprocess.call after this slave.py runs for a period of time then exits.

main.py for insert, (list) in enumerate(list, start =1):      sys.args = [list]     subprocess.call(["python", "slave.py", sys.args], shell = True)   {loop through program and do more stuff..} 

And my slave script

slave.py print sys.args while True:     {do stuff with args in loop till finished}     time.sleep(30) 

Currently, slave.py blocks main.py from running the rest of its tasks, I simply want slave.py to be independent of main.py, once I've passed args to it. The two scripts no longer need to communicate.

I've found a few posts on the net about non blocking subprocess.call but most of them are centered on requiring communication with slave.py at some-point which I currently do not need. Would anyone know how to implement this in a simple fashion...?

like image 655
DavidJB Avatar asked Apr 17 '13 23:04

DavidJB


People also ask

Is Popen wait blocking?

Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.

What is difference between subprocess Popen and call?

Popen is more general than subprocess. call . Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.

Does subprocess call raise exception?

check_call will raise an exception if the command it's running exits with anything other than 0 as its status.

Is Python not blocking?

Usually Python will wait for the response to reach back and then proceeds with sending the next one. This is called Blocking operation. When we do concurrency tasks, we are making the Python code do Non-blocking operation.


1 Answers

You should use subprocess.Popen instead of subprocess.call.

Something like:

subprocess.Popen(["python", "slave.py"] + sys.argv[1:]) 

From the docs on subprocess.call:

Run the command described by args. Wait for command to complete, then return the returncode attribute.

(Also don't use a list to pass in the arguments if you're going to use shell = True).


Here's a MCVE1 example that demonstrates a non-blocking suprocess call:

import subprocess import time  p = subprocess.Popen(['sleep', '5'])  while p.poll() is None:     print('Still sleeping')     time.sleep(1)  print('Not sleeping any longer.  Exited with returncode %d' % p.returncode) 

An alternative approach that relies on more recent changes to the python language to allow for co-routine based parallelism is:

# python3.5 required but could be modified to work with python3.4. import asyncio  async def do_subprocess():     print('Subprocess sleeping')     proc = await asyncio.create_subprocess_exec('sleep', '5')     returncode = await proc.wait()     print('Subprocess done sleeping.  Return code = %d' % returncode)  async def sleep_report(number):     for i in range(number + 1):         print('Slept for %d seconds' % i)         await asyncio.sleep(1)  loop = asyncio.get_event_loop()  tasks = [     asyncio.ensure_future(do_subprocess()),     asyncio.ensure_future(sleep_report(5)), ]  loop.run_until_complete(asyncio.gather(*tasks)) loop.close() 

1Tested on OS-X using python2.7 & python3.6

like image 125
mgilson Avatar answered Sep 23 '22 14:09

mgilson