Run external program concurrently in Python - python

I'm wondering how to call an external program in such a way that allows the user to continue to interact with my program's UI (built using tkinter, if it matters) while the Python program is running. The program waits for the user to select files to copy, so they should still be able to select and copy files while the external program is running. The external program is Adobe Flash Player.
Perhaps some of the difficulty is due to the fact that I have a threaded "worker" class? It updates the progress bar while it does the copying. I would like the progress bars to update even if the Flash Player is open.
I tried the subprocess module. The program runs, however it prevents the user from using the UI until the Flash Player is closed. Also, the copying still seems to occur in the background, it's just that the progress bar does not update until the Flash Player is closed.
def run_clip():
flash_filepath = "C:\\path\\to\\file.exe"
# halts UI until flash player is closed...
subprocess.call([flash_filepath])
Next, I tried using the concurrent.futures module (I was using Python 3 anyway). Since I'm still using subprocess to call the application, it's not surprising that this code behaves exactly like the above example.
def run_clip():
with futures.ProcessPoolExecutor() as executor:
flash_filepath = "C:\\path\\to\\file.exe"
executor.submit(subprocess.call(animate_filepath))
Does the problem lie in using subprocess? If so, is there a better way to call the external program? Thanks in advance.

You just need to keep reading about the subprocess module, specifically about Popen.
To run a background process concurrently, you need to use subprocess.Popen:
import subprocess
child = subprocess.Popen([flash_filepath])
# At this point, the child process runs concurrently with the current process
# Do other stuff
# And later on, when you need the subprocess to finish or whatever
result = child.wait()
You can also interact with the subprocess' input and output streams via members of the Popen-object (in this case child).

Related

How to make cmds.duplicate() execute immediately when called in maya

How to make cmds.duplicate execute immediately when called in maya? Instead of waiting for the entire script to run and then executing it in batches. For example, for this script below, all execution results will appear immediately after the entire script is executed
import time
for i in range(1, 6):
pm.select("pSphere{}".format(i))
time.sleep(0.5)
cmds.duplicate()
I have tried to use python multithreading, like this
import threading
import time
def test():
for i in range(50):
cmds.duplicate('pSphere1')
time.sleep(0.1)
thread = threading.Thread(target=test)
thread.start()
#thread.join()
Sometimes it can success, but sometimes it will crash maya. If the main thread join, it will not achieve the effect. When I want to do a large number of cmds.duplicate, it will resulting in a very high memory consumption, and the program runs more and more slowly. In addition, all duplicate results appear together after the entire python script runs, so I suspect that when I call cmds When duplicating, Maya did not finish executing and outputting the command, but temporarily put the results in a container with variable capacity. With the increase of my calls, the process of dynamic expansion of the container causes the program to become slower and slower, and the memory consumption also increase dramatically. Because I saw that other plug-ins can see the command execution results in real time, so I thought that this should be a proper way to do this just thath I haven't found yet
Your assumptions are not correct. Maya does not need to display anything to complete a tool. If you want to see the results inbetween you can try to use:
pm.refresh()
but this will not change the behaviour in general. I suppose your memory problems have a different source. You could check if it helps to turn off history or the undo queue temporarily.
And of course Ennakard is right with the answer, that most maya commands are not thread save unless mentioned in the docs. Every node creation and modificatons have to be done in the main thread.
The simple answer is you don't, maya command in general and most interaction with maya are not thread safe
threading is usually used for data manipulation before it get used to manipulate anything in maya, but once you start creating node or setting attribute, or any maya modification, no threading.

Stop whole script from one process of multiprocessing

I'm doing a small project related to data engineering. I have 2 processes. First is responsible for sorting, analysing and making graphs. The second is only the loading bar, simple gui which is shown to user why data operators are done. The loading bar stops when the information from multiprocessing Event is send. But I want to stop whole function from second process when user close the window. Basically I want to stop python script when the window is closed. I tried with options:
sys.exit(0), exit(0), quit() and os._exit(0) but every option kills only the process instead of running whole script. I want to do similar option to ctrl+c in vsc terminal. Did I missed sth or it doesn't work in general?

Is there a way I can store the output of a terminal command into a file using python?

I want to store the output of the terminal command top into a file, using Python.
In the terminal, when I type top and hit enter, I get an output that is real time, so it keeps updating. I want to store this into a file for a fixed duration and then stop writing.
file=open("data.txt","w")
file.flush()
import os,time
os.system("top>>data.txt -n 1")
time.sleep(5)
exit()
file.close()
I have tried to use time.sleep() and then exit(), but it doesn't work, and the only way top can be stopped is in the terminal, by Control + C
The process keeps running and the data is continuously written onto the file, which is not ideal, as one would guess
For clarity: I know how to write the output on to the file, I just want to stop writing after a period
system will wait for the end of the child process. If you do not want that, the Pythonic way is to directly use the subprocess module:
import subprocess
timeout=60 # let top run for one minute
file=open("data.txt","w")
top = subprocess.Popen(["top", "-n", 1], stdout=file)
if top.wait(timeout) is None: # wait at most timeout seconds
top.terminate() # and terminate child
The panonoic way (which is highly recommended for robust code) would be to use the full path of top. I have not here, because it may depend on the actual system...
The issue you could be facing is that os.system starts the process as part of the current process. So the rest of your script will not be run until the command you run has completed execution.
I think what you want to be doing is executing your console command on another thread so that the thread running your python script can continue while the command runs in the background. See run a python program on a new thread for more info.
I'd suggest something like (this is untested):
import os
import time
import multiprocessing
myThread = multiprocessing.process(target=os.system, args=("top>>data.txt -n 1",))
myThread.start()
time.sleep(5)
myThread.terminate()
That being said, you may need to consider the thread safety of os.system(), if it is not thread safe you'll need to find an alternative that is.
Something else worth noting (and that I know little about) is that it may not be ideal to terminate threads in this way, see some of the answers here: Is there any way to kill a Thread?

How to immediately kill Python script after running subprocess?

I made a script which plays a video file by using subprocess.run().
import subprocess
DATA_DIR = 'path\\to\\video\\files'
MEDIA_PLAYER = 'path\\to\\my\\media-player'
# returns path of random video file
p = chooseOne(DATA_DIR)
print('playing {}'.format(p))
# runs chosen path
subprocess.run([MEDIA_PLAYER, p])
But I would like to kill the python script running this code immediately after opening the child subprocess.
Is this possible? And if not, is there an alternative means of opening an external process using Python which would allow the script to terminate?
Note: I am using Python v3.6
Don't use subprocess.run; use os.execl instead. That makes your media player replace your Python code in the current process, rather that starting a new process.
os.execl(MEDIA_PLAYER, p)
subprocess.run effectively does the same thing, but forks first so that there are temporarily two processes running your Python script; in one, subprocess.run returns without doing anything else to allow your script to continue. In the other, it immediately uses one of the os.exec* functions—there are 8 different varieties—to execute your media player. In your case, you just want the first process to exit anyway, so save the effort of forking and just use os.execl right away.

How to use threading/multiprocessing to prevent program hanging?

I am a bit confused with multiprocessing. I have a video processing script which can be run from the command line or launched from a PySide application using a subprocess call. The script seems to run fine from the command line and basically initializes a pool of workers which each process a separate video file.
When I run the program however the OS tells me my program is not responding. I would like to make use of all the cores on my system for multiprocessing but I would also like to prevent this annoyance. What should I do I get around this? Do I start the initial script in a thread or something?
As you are speaking of PySide, I assume you program is a GUI one. In a GUI program all processing must occurs in a worker thread if you want to keep the UI responsive. So yes, the initial script must be start in a thread distinct from main thread (main one is reserved for UI)

Categories

Resources