2014-12-23 16 views
11

tôi muốn bắt đầu một quá trình từ kịch bản python của tôi (main.py), đặc biệt là tôi muốn chạy lệnh dưới đâyKhởi chạy một quá trình hoàn toàn độc lập

`nohup python ./myfile.py &` 

và tập tin này myfile.py nên ngay cả sau khi thoát python script chính của tôi.

Ngoài ra, tôi muốn nhận được pid của quy trình mới.

tôi đã cố gắng os.spawnl*, os.exec* & subprocess.Popen phương pháp, tất cả đều chấm dứt của tôi myfile.py nếu kịch bản main.py tôi thoát.

Tôi có thể thiếu điều gì đó.

Cập nhật: Tôi có thể sử dụng os.startfile với xdg-open không? Đó có phải là một cách tiếp cận đúng không?

Ví dụ

a = subprocess.Popen([sys.executable, "nohup /usr/bin/python25 /long_process.py &"],\ 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 
print a.pid 

Nếu tôi kiểm tra ps aux | grep long_process, tôi không thể nhìn thấy bất kỳ quá trình chạy.

long_process.py tiếp tục in một số văn bản: không thoát.

Tôi có làm gì sai ở đây không?

+0

Bạn có thể đăng một ví dụ tối thiểu không hoạt động được không? Sau một quy trình con nhập khẩu 'python -c 'tầm thường; subprocess.Popen (["sleep", "60"]) ''đầu ra của' ps' cho thấy rằng 'sleep' tiếp tục chạy tốt sau khi Python đã thoát. – user4815162342

+0

Bạn đang chạy Python với một đối số duy nhất, '" nohup/usr/bin/python25 ... "', không thể hoạt động vì tệp thực thi 'python' sẽ tìm kiếm tập lệnh trong tệp có tên chính xác là' nohup/usr/bin/... ', không tồn tại. Và vì bạn chỉ định 'stderr' là' PIPE' mà không bao giờ đọc nội dung của đường ống, bạn sẽ không bao giờ thấy thông báo lỗi. Mất 'nohup' và' & ', và chỉ cần chạy' subprocess.Popen ([sys.executable, "/.../ long_process.py"]) '. Ngoài ra, không chỉ định 'stdin' và' stderr' làm đường ống trừ khi bạn muốn nói. – user4815162342

+0

'nohup' có ý nghĩa nhất khi bạn bắt đầu quá trình từ trình bao. Tôi không thấy 'shell = True' trong cuộc gọi' Popen' của bạn. – 9000

Trả lời

10

Bạn mở quy trình chạy dài của mình và giữ đường ống đến số. Vì vậy, bạn mong đợi để nói chuyện với nó. Khi kịch bản trình khởi chạy yor thoát, bạn không còn có thể nói chuyện với nó nữa. Quá trình chạy dài nhận được SIGPIPE và thoát.

Chỉ làm việc sau đây cho tôi (Linux, Python 2.7).

Tạo một dài chạy thực thi:

$ echo "sleep 100" > ~/tmp/sleeper.sh 

Chạy Python REPL:

$ python 
>>> 

import subprocess 
import os 
p = subprocess.Popen(['/bin/sh', os.path.expanduser('~/tmp/sleeper.sh')]) 
# look ma, no pipes! 
print p.pid 
# prints 29893 

Thoát REPL và xem quá trình này vẫn chạy:

>>> ^D 
$ ps ax | grep sleeper 
29893 pts/0 S  0:00 /bin/sh .../tmp/sleeper.sh 
29917 pts/0 S+  0:00 grep --color=auto sleeper 

Nếu bạn muốn đầu tiên giao tiếp với quá trình bắt đầu và sau đó để nó một mình để chạy xa hơn, bạn có một vài tùy chọn:

  • Xử lý SIGPIPE trong quá trình chạy dài của bạn, đừng chết trên đó. Sống mà không có stdin sau khi quá trình khởi chạy thoát.
  • Vượt qua bất kỳ điều gì bạn muốn bằng cách sử dụng đối số, môi trường hoặc tệp tạm thời.
  • Nếu bạn muốn liên lạc hai chiều, hãy cân nhắc sử dụng một đường ống có tên (man mkfifo) hoặc một ổ cắm hoặc viết một máy chủ phù hợp.
  • Làm cho ngã ba quá trình chạy dài sau khi giai đoạn truyền thông hai chiều ban đầu được thực hiện.
+0

Câu trả lời hay, đó là một điểm tốt mà quá trình chết do 'SIGPIPE'. (Trong mã từ câu hỏi quá trình không bao giờ bắt đầu, nhưng OP cũng có thể đã thử các biến thể khác đã bắt đầu và chết do 'SIGPIPE'.) – user4815162342

+0

Nó không tạo ra" một quá trình hoàn toàn độc lập "(rằng những gì' python -daemon' gói). Ngoài ra, [một tiến trình con sẽ không nhận được SIGPIPE trong Python 2] (http://stackoverflow.com/a/22083141/4279). Mặc dù trong các trường hợp đơn giản, giải pháp của bạn là đủ (bạn nên chuyển hướng tới stdin/stdout/stderr của 'os.devnull' để tránh phải chờ đầu vào và/hoặc đầu ra giả cho thiết bị đầu cuối). – jfs

+0

@ user4815162342: Nó sẽ không chết do SIGPIPE trong Python 2 (câu hỏi có thẻ [tag: python2.7]). – jfs

5

Bạn có thể sử dụng os.fork().

import os 
pid=os.fork() 
if pid==0: # new process 
    os.system("nohup python ./myfile.py &") 
    exit() 
# parent process continues 
+0

Nó hoạt động +1, tuy nhiên Popen rất thoải mái. – Garfield

3

Tôi không thể thấy bất kỳ quy trình nào đang chạy.

Bạn không thấy bất kỳ quy trình nào đang chạy vì quá trình con python thoát ngay lập tức. Các đối số Popen không chính xác là @user4815162342 says in the comment.

Để khởi động một hoàn toàn độc lập quá trình, bạn nên sử dụng python-daemon package:

#!/usr/bin/python25 
import daemon 
from long_process import main 

with daemon.DaemonContext(): 
    main() 

Mặc dù nó có thể là đủ trong trường hợp của bạn, để bắt đầu con với đúng Popen đối số:

with open(os.devnull, 'r+b', 0) as DEVNULL: 
    p = Popen(['/usr/bin/python25', '/path/to/long_process.py'], 
       stdin=DEVNULL, stdout=DEVNULL, stderr=STDOUT, close_fds=True) 
time.sleep(1) # give it a second to launch 
if p.poll(): # the process already finished and it has nonzero exit code 
    sys.exit(p.returncode) 

Nếu quá trình con không yêu cầu python2.5 thì bạn có thể sử dụng sys.executable thay thế (để sử dụng cùng một phiên bản Python làm cha mẹ).

Lưu ý: mã đóng DEVNULL trong phụ huynh mà không cần chờ quá trình con hoàn thành (nó không ảnh hưởng đến trẻ).

Các vấn đề liên quan