How to delay the execution of a script in Python? - python

I'm working with a Python script and I have some problems on delaying the execution of a Bash script.
My script.py lets the user choose a script.sh, and after the possibility to modify that, the user can run it with various options.
One of this option is the possibility to delay of N seconds the execution of the script, I used time.sleep(N) but the script.py totally stops for N seconds, I just want to retard the script.sh of N seconds, letting the user continue using the script.py.
I searched for answers without success, any ideas?

You can start the script in a New thread, sleeping before running it.
Minimal example:
import subprocess as sp
from threading import Thread
import time
def start_delayed(args, delay):
time.sleep(delay)
sp.run(args)
t = Thread(target=start_delayed, kwargs={'args': ['ls'], 'delay': 5})
t.start()

Consider using a Timer object from the threading module:
import subprocess, threading
t = threading.Timer(10.0, subprocess.call, args=(['script.sh'],))
t.start()
...the above running script.sh after a 10-second delay.
Alternately, if you want to efficiently be able to run an arbitrary number of scheduled tasks with only a single thread controlling them, consider using a scheduler from the tandard-library sched module:
import sched, subprocess
s = sched.scheduler(time.time, time.sleep)
s.enter(10, subprocess.call, (['script.sh'],))
s.run()
This will run script.sh after 10 seconds have passed -- though if you want it to run in the background, you'll want to put it in a thread (or such) yourself.

You should run sleep using subprocess.Popen before calling script.sh.

Related

Run multiple processes in parallel, continue each after each finishes

I'm on Windows environment, and suppose I have two toy programs, called 2.bat and 5.bat, which look like timeout 2 and timeout 5, respectively.
I want to set up a script that runs both 2.bat and 5.bat in parallel, and when 2.bat finishes it is ran again and likewise for 5.bat. I'm pretty bad at Python, but after a bit of searching I see that I can do:
from subprocess import Popen
commands = ["2.bat", "5.bat"]
while True:
procs = [Popen(i) for i in commands]
for p in procs:
p.wait()
This doesn't do what I want: it waits for both processes to finish, and then again executes both. What I want to do (in pseudocode) is as follows:
while True:
in parallel, run 2.bat and 5.bat
when 2.bat finishes, rerun 2.bat again
when 5.bat finishes, rerun 5.bat again
Can I achieve this with subprocess, or do I need other libraries?
my solution would be:
from _thread import start_new_thread
from subprocess import Popen
commands = ["2.bat", "5.bat"]
def run_bat(file):
while True:
p = Popen(file)
p.wait()
for command in commands:
start_new_thread(run_bat, (command, ))
while True:
pass

Threading using less RAM than Popen, why?

I have a question, So I am testing RAM usage of my script and it is as easy as:
a script that is a start up, that script opens up 4 python script in a while loop and loops forever.
I tested 2 things. One with just calling Popen for each script and one using threading and I found out that there is a huge difference between each other...
The script with threading:
And a script that uses Popen to open up the scripts:
Since they both do the exact same thing, why does the Python threading uses so much less RAM than the other that opens up the script? What are the advantage vs. disadvantage of using the threading vs. Popen?
test2:
import time
def testing():
while True:
test = "Helllo world"
print(test)
time.sleep(1)
if __name__ == '__main__':
testing()
threading.py:
import threading
from test2 import testing
threading.Thread(target=testing()).start()
threading.Thread(target=testing()).start()
threading.Thread(target=testing()).start()
Popen:
from subprocess import Popen
for _ in range(4):
Popen(f"py test2.py", shell=True).communicate()
The popen() version creates 3 whole new processes, each of which runs its own, distinct Python interpreter.
The threading version run 3 threads within the current process, sharing its memory space and the single, original Python interpreter.

Loop-execution of a set of Python scripts with arguments from the main script

I have a child python script that takes an argument and takes approx. 8 minutes to run.
e.g. python.exe child.py "2018-01-01"
I need to execute this script many times from a main script. I am considering using subprocess.Popen.
import os, sys, time, subprocess
for date in ["2018-01-01", "2018-01-02", "2018-01-03", ..., "2018-12-31"]
p = subprocess.Popen(['python.exe', "child.py", date])
time.sleep(600)
As the Popen function does not know when the child script finishes executing, it just keeps triggering the child script with the argument. So I had to need to set 600 seconds of sleep time (longer than the approximate run time for the child script) so the subsequent run safely starts after the previous run finishes.
I wonder if there is a more efficient way to dealing this situation.
If the scripts need to run synchronously, consider using subprocess. More specifilcally, the run function (>=3.5). Or even the call function (<3.5), which is the same as run but it only returns the code from the script. Both block the calling script until return.
Your code would become:
import shlex
import subprocess
for date in ["2018-01-01", "2018-01-02", "2018-01-03", ..., "2018-12-31"]:
command = 'python.exe child.py %s' % date
args = shlex.split(command)
res = subprocess.run(args)
If you need it to run asyncrhonously, consider using xargs. If you really need to do it in python, use multiprocessing our multiprocessing.dummy to do it.
how about this, call the wait() so the current subprocess is done before launching another one.
for date in ["2018-01-01", "2018-01-02", "2018-01-03", ..., "2018-12-31"]
p = subprocess.Popen(['python.exe', "child.py", date])
p.wait()
rc = p.returncode
print(rc)

Running function as a thread in background python and exit before its application

I'm executing a function as a thread in python. Now, the program will wait for the function to execute and then terminate after its completion.
My target is to starting the background thread and closing the program calling it.
how can we do it. As in below code, the thread will take 30 min to execute. I want to stop the main program after calling the thread and let the thread run in background.
thread = threading.Thread(target=function_that_runs_for_30_min)
thread.start()
print "Thread Started"
quit()
You cannot do that directly. A thread is just a part of a process. Once the process exits, all the threads are gone. You need to create a background process to achieve that.
You cannot use the multiprocessing module either because it is a package that supports spawning processes using an API similar to the threading module (emphasize mine). As such it has no provision to allow a process to run after the end of the calling one.
The only way I can imagine is to use the subprocess module to restart the script with a specific parameter. For a simple use case, adding a parameter is enough, for more complex command line parameters, the module argparse should be used. Example of code:
import subprocess
import sys
# only to wait some time...
import time
def f(name):
"Function that could run in background for a long time (30')"
time.sleep(5)
print 'hello', name
if __name__ == '__main__':
if (len(sys.argv) > 1) and (sys.argv[1] == 'SUB'):
# Should be an internal execution: start the lengthy function
f('bar')
else:
# normal execution: start a subprocess with same script to launch the function
p = subprocess.Popen("%s %s SUB" % (sys.executable, sys.argv[0]))
# other processing...
print 'END of normal process'
Execution:
C:\>python foo.py
END of normal process
C:\>
and five seconds later:
hello bar

Python subprocess.call thread hang, subprocess.popen no hang

I am trying to automate the installation of a specific program using Sikuli and scripts on Windows 7. I needed to start the program installer and then used Siluki to step through the rest of the installation. I did this using Python 2.7
This code works as expected by creating a thread, calling the subprocess, and then continuing the main process:
import subprocess
from threading import Thread
class Installer(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
subprocess.Popen(["msiexec", "/i", "c:\path\to\installer.msi"], shell=True)
i = Installer()
i.run()
print "Will show up while installer is running."
print "Other things happen"
i.join()
This code does not operate as desired. It will start the installer but then hang:
import subprocess
from threading import Thread
class Installer(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
subprocess.call("msiexec /i c:\path\to\installer.msi")
i = Installer()
i.run()
print "Will not show up while installer is running."
print "Other things happen"
i.join()
I understand that subprocess.call will wait for the process to terminate. Why does that prevent the main thread from continuing on? Should the main continue execution immediately after the process call?
Why is there such a difference in behaviors?
I have only just recently started using threads C.
You're calling i.run(), but what you should be calling is i.start(). start() invokes run() in a separate thread, but calling run() directly will execute it in the main thread.
First.
you need to add the command line parameters to your install command to make it a silent install..
http://msdn.microsoft.com/en-us/library/aa372024%28v=vs.85%29.aspx
the subprocess is probably hung waiting for an install process that will never end because it is waiting for user input.
Second.
if that doesn't work.. you should be using popen and communicate
How to use subprocess popen Python
Third.
if that still didn't work, your installer is hanging some where and you should debug the underlying process there.

Categories

Resources