Berikut kode Python untuk menjalankan perintah sewenang-wenang mengembalikan stdout
datanya, atau meningkatkan pengecualian pada kode keluar non-nol:
proc = subprocess.Popen(
cmd,
stderr=subprocess.STDOUT, # Merge stdout and stderr
stdout=subprocess.PIPE,
shell=True)
communicate
digunakan untuk menunggu proses keluar:
stdoutdata, stderrdata = proc.communicate()
The subprocess
modul tidak mendukung batas waktu - kemampuan untuk membunuh proses yang berjalan selama lebih dari X jumlah detik - Oleh karena itu, communicate
dapat mengambil selamanya untuk menjalankan.
Apa cara paling sederhana untuk mengimplementasikan timeout dalam program Python yang dimaksudkan untuk berjalan di Windows dan Linux?
python
multithreading
timeout
subprocess
Sridhar Ratnakumar
sumber
sumber
Jawaban:
Dengan Python 3.3+:
output
adalah string byte yang berisi stdout, stderr data perintah yang digabungkan.check_output
meningkatkanCalledProcessError
status keluar non-nol seperti yang ditentukan dalam teks pertanyaan ini tidak sepertiproc.communicate()
metode.Saya telah menghapusnya
shell=True
karena sering digunakan secara tidak perlu. Anda selalu dapat menambahkannya kembali jikacmd
memang membutuhkannya. Jika Anda menambahkanshell=True
yaitu, jika proses anak memunculkan keturunannya sendiri;check_output()
dapat kembali lebih lama dari batas waktu yang ditunjukkan, lihat Kegagalan batas waktu proses .Fitur batas waktu tersedia di Python 2.x melalui
subprocess32
backport modul subproses 3.2+.sumber
check_output()
adalah cara yang disukai untuk mendapatkan output (mengembalikan output secara langsung, tidak mengabaikan kesalahan, tersedia sejak selamanya). 2-run()
lebih fleksibel tetapirun()
mengabaikan kesalahan secara default dan membutuhkan langkah-langkah tambahan untuk mendapatkan output 3-check_output()
diimplementasikan dalam halrun()
dan karenanya menerima sebagian besar argumen yang sama. 4- nit:capture_output
tersedia sejak 3,7, bukan 3,5Saya tidak tahu banyak tentang detail level rendah; tetapi, mengingat bahwa dalam python 2.6 API menawarkan kemampuan untuk menunggu utas dan mengakhiri proses, bagaimana dengan menjalankan proses dalam utas terpisah?
Output potongan ini di mesin saya adalah:
di mana dapat dilihat bahwa, dalam eksekusi pertama, proses selesai dengan benar (kode kembali 0), sedangkan yang kedua proses dihentikan (kode kembali -15).
Saya belum menguji di windows; tetapi, selain dari memperbarui contoh perintah, saya pikir itu harus berfungsi karena saya belum menemukan apa pun di dokumentasi yang mengatakan bahwa thread.join atau process.terminate tidak didukung.
sumber
Jawaban jcollado dapat disederhanakan menggunakan kelas threading.Timer :
sumber
lambda
:t = Timer(timeout, proc.kill)
timer.isAlive()
sebelumtimer.cancel()
berarti berakhir dengan normalJika Anda menggunakan Unix,
sumber
Berikut ini solusi Alex Martelli sebagai modul dengan proses pembunuhan yang tepat. Pendekatan lain tidak berfungsi karena mereka tidak menggunakan proc.communicate (). Jadi, jika Anda memiliki proses yang menghasilkan banyak output, itu akan mengisi buffer outputnya dan kemudian memblokir sampai Anda membaca sesuatu darinya.
sumber
ValueError: signal only works in main thread
Saya telah memodifikasi jawaban sussudio . Sekarang berfungsi kembali: (
returncode
,stdout
,stderr
,timeout
) -stdout
danstderr
diterjemahkan ke utf-8 stringsumber
terkejut tidak ada yang disebutkan menggunakan
timeout
timeout 5 ping -c 3 somehost
Ini tidak akan berfungsi untuk setiap kasus penggunaan jelas, tetapi jika Anda berurusan dengan skrip sederhana, ini sulit dikalahkan.
Juga tersedia sebagai gtimeout di coreutils via
homebrew
untuk pengguna mac.sumber
proc = subprocess.Popen(['/usr/bin/timeout', str(timeout)] + cmd, ...)
. Apakah adatimeout
perintah di Windows saat OP bertanya?timeout
sekarang didukung olehcall()
dancommunicate()
dalam modul subproses (pada Python3.3):Ini akan memanggil perintah dan memunculkan eksepsi
jika perintah tidak selesai setelah 20 detik.
Anda kemudian dapat menangani pengecualian untuk melanjutkan kode Anda, seperti:
Semoga ini membantu.
sumber
timeout
parameter . Meskipun menyebutkannya sekali lagi tidak ada salahnya.Pilihan lain adalah menulis ke file sementara untuk mencegah pemblokiran stdout alih-alih perlu polling dengan komunikasi (). Ini bekerja untuk saya di mana jawaban yang lain tidak; misalnya di windows.
sumber
Saya tidak tahu mengapa itu tidak disebutkan tetapi karena Python 3.5, ada
subprocess.run
perintah universal baru (yang dimaksudkan untuk menggantikancheck_call
,check_output
...) dan yang memilikitimeout
parameter juga.Ini menimbulkan
subprocess.TimeoutExpired
pengecualian ketika batas waktu berakhir.sumber
Ini solusi saya, saya menggunakan Thread and Event:
Beraksi:
sumber
Solusi yang saya gunakan adalah untuk awalan perintah shell dengan timelimit . Jika perintah terlalu lama, timelimit akan menghentikannya dan Popen akan memiliki kode pengembalian yang ditetapkan oleh timelimit. Jika itu> 128, itu berarti timelimit membunuh proses.
Lihat juga subproses python dengan batas waktu dan keluaran besar (> 64K)
sumber
timeout
- packages.ubuntu.com/search?keywords=timeout - tetapi tidak berfungsi di Windows, bukan?Saya menambahkan solusi dengan threading dari
jcollado
ke modul Python saya easyprocess saya .Install:
Contoh:
sumber
jika Anda menggunakan python 2, cobalah
sumber
Mempertahankan perintah Linux
timeout
bukanlah solusi yang buruk dan berhasil bagi saya.sumber
Saya sudah menerapkan apa yang bisa saya kumpulkan dari beberapa di antaranya. Ini berfungsi di Windows, dan karena ini adalah wiki komunitas, saya pikir saya juga akan membagikan kode saya:
Kemudian dari kelas atau file lain:
sumber
terminate()
tanda fungsi benang sebagai dihentikan, tetapi tidak benar-benar mengakhiri benang! Saya dapat memverifikasi ini di * nix, tetapi saya tidak memiliki komputer Windows untuk diuji.Setelah Anda memahami proses penuh menjalankan mesin di * unix, Anda akan dengan mudah menemukan solusi yang lebih sederhana:
Pertimbangkan contoh sederhana ini bagaimana membuat komunikasi timeoutable () meth menggunakan select.select () (tersedia hampir semua tempat di * nix saat ini). Ini juga dapat ditulis dengan epoll / poll / kqueue, tetapi varian select.select () bisa menjadi contoh yang baik untuk Anda. Dan batasan utama select.select () (kecepatan dan 1024 maks fds) tidak dapat diterapkan untuk tugas Anda.
Ini berfungsi di bawah * nix, tidak membuat utas, tidak menggunakan sinyal, dapat diluncurkan dari utas apa pun (tidak hanya utama), dan cukup cepat untuk membaca 250mb / s data dari stdout pada mesin saya (i5 2.3ghz).
Ada masalah saat bergabung dengan stdout / stderr di akhir komunikasi. Jika Anda memiliki output program yang besar, ini dapat menyebabkan penggunaan memori yang besar. Tetapi Anda dapat memanggil berkomunikasi () beberapa kali dengan batas waktu yang lebih kecil.
sumber
Anda dapat melakukan ini menggunakan
select
sumber
Saya telah menggunakan proses killableproses dengan sukses di Windows, Linux dan Mac. Jika Anda menggunakan Cygwin Python, Anda akan memerlukan proses killableproses versi OSAF karena jika tidak, proses Windows asli tidak akan terbunuh.
sumber
Meskipun saya belum melihatnya secara luas, dekorator yang saya temukan di ActiveState ini tampaknya cukup berguna untuk hal semacam ini. Seiring dengan
subprocess.Popen(..., close_fds=True)
, setidaknya saya siap untuk shell-scripting dengan Python.sumber
Solusi ini membunuh pohon proses jika shell = True, meneruskan parameter ke proses (atau tidak), memiliki batas waktu dan mendapatkan stdout, stderr dan memproses output dari panggilan balik (menggunakan psutil untuk kill_proc_tree). Ini didasarkan pada beberapa solusi yang diposting di SO termasuk jcollado. Posting dalam menanggapi komentar oleh Anson dan jradice dalam jawaban jcollado. Diuji pada Windows Srvr 2012 dan Ubuntu 14.04. Harap dicatat bahwa untuk Ubuntu Anda perlu mengubah panggilan parent.children (...) ke parent.get_children (...).
sumber
Ada ide untuk mensubkelas kelas Popen dan memperluasnya dengan beberapa dekorator metode sederhana. Sebut saja ExpiredPopen.
sumber
Saya memiliki masalah yang ingin saya hentikan sub-proses multithreading jika perlu waktu lebih lama dari batas waktu yang diberikan. Saya ingin mengatur batas waktu
Popen()
, tetapi tidak berhasil. Kemudian, saya menyadari bahwaPopen().wait()
itu sama dengancall()
dan jadi saya punya ide untuk menetapkan batas waktu dalam.wait(timeout=xxx)
metode, yang akhirnya berhasil. Jadi, saya memecahkannya dengan cara ini:sumber
Sayangnya, saya terikat oleh kebijakan yang sangat ketat tentang pengungkapan kode sumber oleh majikan saya, jadi saya tidak bisa memberikan kode yang sebenarnya. Tapi untuk seleraku solusi terbaik adalah membuat subclass overriding
Popen.wait()
untuk polling daripada menunggu tanpa batas waktu, danPopen.__init__
menerima parameter timeout. Setelah Anda melakukannya, semuaPopen
metode lain (panggilan ituwait
) akan berfungsi seperti yang diharapkan, termasukcommunicate
.sumber
https://pypi.python.org/pypi/python-subprocess2 memberikan ekstensi ke modul subproses yang memungkinkan Anda untuk menunggu periode waktu tertentu, jika tidak berakhir.
Jadi, untuk menunggu hingga 10 detik agar proses berakhir, jika tidak bunuh:
Ini kompatibel dengan windows dan unix. "hasil" adalah kamus, ini berisi "returnCode" yang merupakan kembalinya aplikasi (atau tidak ada jika harus dibunuh), serta "actionTaken". yang akan menjadi "SUBPROCESS2_PROCESS_COMPLETED" jika proses selesai secara normal, atau topeng "SUBPROCESS2_PROCESS_TERMINATED" dan SUBPROCESS2_PROCESS_KILLED tergantung pada tindakan yang diambil (lihat dokumentasi untuk detail lengkap)
sumber
untuk python 2.6+, gunakan gevent
sumber
python 2.7
sumber
sumber
Hanya mencoba menulis sesuatu yang lebih sederhana.
sumber