Python 스크립트에서 비동기 적으로 셸 명령을 실행해야합니다. 이것은 외부 명령이 꺼지고 필요한 모든 작업을 수행하는 동안 Python 스크립트가 계속 실행되기를 원한다는 것을 의미합니다.
이 게시물을 읽었습니다.
그런 다음 나가서 몇 가지 테스트 os.system()
를 수행 &
했으며 명령이 끝날 때까지 기다릴 필요가 없도록 명령 끝에서 사용하는 경우 작업을 수행 할 것 같습니다 . 내가 궁금한 것은 이것이 그러한 일을 수행하는 적절한 방법인지입니다. 시도 commands.call()
했지만 외부 명령을 차단하기 때문에 작동하지 않습니다.
os.system()
이것을 위해 사용 하는 것이 바람직하거나 다른 경로를 시도 해야하는지 알려주십시오 .
답변
subprocess.Popen 은 정확히 원하는 작업을 수행합니다.
from subprocess import Popen
p = Popen(['watch', 'ls']) # something long running
# ... do other stuff while subprocess is running
p.terminate()
(댓글에서 답변을 완성하려면 편집)
Popen 인스턴스 poll()
는 여전히 실행 중인지 확인하고 communicate()
stdin에서 데이터를 보내고 종료 될 때까지 기다릴 수있는 등 다양한 작업을 수행 할 수 있습니다 .
답변
여러 프로세스를 병렬로 실행하고 결과가 나올 때 처리하려면 다음과 같이 폴링을 사용할 수 있습니다.
from subprocess import Popen, PIPE
import time
running_procs = [
Popen(['/usr/bin/my_cmd', '-i %s' % path], stdout=PIPE, stderr=PIPE)
for path in '/tmp/file0 /tmp/file1 /tmp/file2'.split()]
while running_procs:
for proc in running_procs:
retcode = proc.poll()
if retcode is not None: # Process finished.
running_procs.remove(proc)
break
else: # No process is done, wait a bit and check again.
time.sleep(.1)
continue
# Here, `proc` has finished with return code `retcode`
if retcode != 0:
"""Error handling."""
handle_results(proc.stdout)
제어 흐름은 약간 복잡합니다. 제가 그것을 작게 만들려고하기 때문입니다. 취향에 맞게 리팩토링 할 수 있습니다. 🙂
이것은 초기 완료 요청을 먼저 처리하는 이점이 있습니다. communicate
첫 번째 실행중인 프로세스 를 호출 하고 가장 오래 실행되는 것으로 판명되면 다른 실행중인 프로세스는 결과를 처리 할 수있을 때 유휴 상태에있게됩니다.
답변
내가 궁금한 것은이 [os.system ()]이 그러한 일을 수행하는 적절한 방법인지 여부입니다.
아니요 os.system()
. 올바른 방법이 아닙니다. 그래서 모든 사람들이 subprocess
.
자세한 내용은 http://docs.python.org/library/os.html#os.system을 참조하십시오.
하위 프로세스 모듈은 새 프로세스를 생성하고 결과를 검색하기위한보다 강력한 기능을 제공합니다. 이 기능을 사용하는 것보다 해당 모듈을 사용하는 것이 좋습니다. 하위 프로세스 모듈을 사용하십시오. 특히 이전 기능을 하위 프로세스 모듈로 교체 섹션을 확인하십시오.
답변
나는 프로세스의 출력을 잘 처리 하는 asyncproc 모듈로 좋은 성공을 거두었습니다 . 예를 들면 :
import os
from asynproc import Process
myProc = Process("myprogram.app")
while True:
# check to see if process has ended
poll = myProc.wait(os.WNOHANG)
if poll is not None:
break
# print any new output
out = myProc.read()
if out != "":
print out
답변
non-blocking readlines와 함께 pexpect 를 사용 하는 것도이를위한 또 다른 방법입니다. Pexpect는 교착 상태 문제를 해결하고, 프로세스를 백그라운드에서 쉽게 실행할 수 있으며, 프로세스가 사전 정의 된 문자열을 뱉어 낼 때 콜백을 쉽게 할 수있는 방법을 제공하고 일반적으로 프로세스와의 상호 작용을 훨씬 쉽게 만듭니다.
답변
“돌아올 때까지 기다릴 필요가 없습니다”를 고려할 때 가장 쉬운 해결책 중 하나는 다음과 같습니다.
subprocess.Popen( \
[path_to_executable, arg1, arg2, ... argN],
creationflags = subprocess.CREATE_NEW_CONSOLE,
).pid
하지만 … 제가 읽은 바에 따르면 이것은 “이러한 일을 수행하는 적절한 방법”이 아닙니다. subprocess.CREATE_NEW_CONSOLE
플래그에 .
여기서 일어나는 핵심은를 사용 subprocess.CREATE_NEW_CONSOLE
하여 새 콘솔을 만들고 .pid
(원할 경우 나중에 프로그램을 확인할 수 있도록 프로세스 ID를 반환) 프로그램이 작업을 완료 할 때까지 기다리지 않도록하는 것입니다.
답변
Python에서 s3270 스크립팅 소프트웨어를 사용하여 3270 터미널에 연결하는 데 동일한 문제가 있습니다. 이제 여기에서 찾은 Process의 하위 클래스로 문제를 해결하고 있습니다.
http://code.activestate.com/recipes/440554/
다음은 파일에서 가져온 샘플입니다.
def recv_some(p, t=.1, e=1, tr=5, stderr=0):
if tr < 1:
tr = 1
x = time.time()+t
y = []
r = ''
pr = p.recv
if stderr:
pr = p.recv_err
while time.time() < x or r:
r = pr()
if r is None:
if e:
raise Exception(message)
else:
break
elif r:
y.append(r)
else:
time.sleep(max((x-time.time())/tr, 0))
return ''.join(y)
def send_all(p, data):
while len(data):
sent = p.send(data)
if sent is None:
raise Exception(message)
data = buffer(data, sent)
if __name__ == '__main__':
if sys.platform == 'win32':
shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n')
else:
shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')
a = Popen(shell, stdin=PIPE, stdout=PIPE)
print recv_some(a),
for cmd in commands:
send_all(a, cmd + tail)
print recv_some(a),
send_all(a, 'exit' + tail)
print recv_some(a, e=0)
a.wait()