How can I run an external command asynchronously from Python?
subprocess.Popen
does exactly what you want.
from subprocess import Popen
p = Popen(['watch', 'ls']) # something long running
# ... do other stuff while subprocess is running
p.terminate()
(Edit to complete the answer from comments)
The Popen instance can do various other things like you can poll()
it to see if it is still running, and you can communicate()
with it to send it data on stdin, and wait for it to terminate.
Using asyncio to run command in a time interval and terminate it afterwards
os.system
is a blocking operation, so it doesn't play well with asyncio
. Whenever you use asyncio
, all "longer" operations need to be asynchronous, or you lose all benefits of going with asyncio
in the first place.
import asyncio
async def cmd():
try:
proc = await asyncio.create_subprocess_shell(
"sleep 2 && date > my.txt",
shell=True,
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL)
await proc.communicate()
except asyncio.CancelledError:
proc.terminate()
print("X")
async def run():
try:
await asyncio.wait_for(cmd(), 1)
print("A")
except asyncio.TimeoutError:
print("B")
asyncio.run(run())
As @dim mentions in comments, asyncio.create_subprocess_exec
will launch an external command asynchronously. wait_for
will actually raise two exceptions: TimeoutError
in the awaiting code, and CancelledError
in the awaited code. We can use the latter to realise the operation was cancelled, and to terminate
or kill
our subprocess (as this is not done automatically).
How can I run a terminal command asynchronously using Python?
It looks like you are trying to make an RFCOMM connection.
Both rfcomm
and hcitool
have been deprecated by the BlueZ project back in 2017 so I wouldn't recommend starting a project using these.
BlueZ has APIs that are designed to be accessed from languages like Python and these are documented at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc and the official examples are at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test
However, RFCOMM (or Serial Port Profile) connections can be done with the socket library in the standard Python releases. There are examples at https://stackoverflow.com/a/63382835/7721752
There are also examples in the above answer of using the Bluedot library to do the same.
How to asynchronously call a shell script from Python?
subprocess.call() and subprocess.run() creates a process, waits for it to finish, and returns a CompletedProcess object.
subprocess.Popen() creates a process and returns it. It is used under the hood of the previous functions. You can then wait for the process to finish, send it messages, or whatever else you want to do with it. The arguments are mostly the same as to call
or run
.
https://docs.python.org/3/library/subprocess.html
As a bit of elaboration, Popen is the python implementation of using the os to start a new process. os.fork() is a lower level that doesn't actually do what we want here, that would spawn another instance of the python interpreter with the same memory state as the current one. If you wanted to use the lower level syscall, os.spawn
is closer to subprocess.run
than os.fork
.
To verify that Popen is doing what you want, this test program will pring "returncode = None", then wait 5 seconds, and print "returncode = 0"
from subprocess import Popen
p = Popen(["sleep", "5"])
print("started the proc") # this will print immediately
p.poll() # this checks if the process is done but does not block
print(f"p returncode = {p.returncode}")
p.wait() # this blocks until the process exits
print(f"p returncode = {p.returncode}")
How can I call an async function inside a command in discord python?
The answer to this question is to add an await.
before your async function.
@client.command()
async def hello(ctx):
await ctx.send('hello')
await facts(ctx)
async def facts(ctx):
await ctx.send('facts')
And there you'd be able to call your async function.
Asynchronously receive output from long running shell commands with asyncio (Python 3.4+)?
Use get_lines()
coroutines, to get shell commands output asynchronously and pass the coroutines to asyncio.as_completed()
, to get the results in the order they finish:
#!/usr/bin/env python3.5
import asyncio
import sys
from asyncio.subprocess import PIPE, STDOUT
async def get_lines(shell_command):
p = await asyncio.create_subprocess_shell(shell_command,
stdin=PIPE, stdout=PIPE, stderr=STDOUT)
return (await p.communicate())[0].splitlines()
async def main():
# get commands output concurrently
coros = [get_lines('"{e}" -c "print({i:d}); import time; time.sleep({i:d})"'
.format(i=i, e=sys.executable))
for i in reversed(range(5))]
for f in asyncio.as_completed(coros): # print in the order they finish
print(await f)
if sys.platform.startswith('win'):
loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Related Topics
How to Detect Whether a Python Variable Is a Function
Socketserver.Threadingtcpserver - Cannot Bind to Address After Program Restart
Numpy Selecting Specific Column Index Per Row by Using a List of Indexes
Googletrans Stopped Working with Error 'Nonetype' Object Has No Attribute 'Group'
Grouping Python Dictionary Keys as a List and Create a New Dictionary with This List as a Value
How to Mock an Open Used in a with Statement (Using the Mock Framework in Python)
Why Does Using 'Arg=None' Fix Python's Mutable Default Argument Issue
How to Get List of Methods in a Python Class
Change the Color of Text Within a Pandas Dataframe HTML Table Python Using Styles and CSS
Python in Raw Mode Stdin Print Adds Spaces
How to Write to a CSV Line by Line
How to Get the Input from the Tkinter Text Widget