Apakah ada cara Pythonic agar hanya satu contoh dari program yang berjalan?
Satu-satunya solusi masuk akal yang saya temukan adalah mencoba menjalankannya sebagai server di beberapa port, lalu program kedua mencoba mengikat ke port yang sama - gagal. Tapi itu bukan ide yang bagus, mungkin ada sesuatu yang lebih ringan dari ini?
(Pertimbangkan bahwa program terkadang gagal, yaitu segfault - jadi hal-hal seperti "file kunci" tidak akan berfungsi)
python
process
locking
mutual-exclusion
Slava V
sumber
sumber
Jawaban:
Kode berikut harus melakukan pekerjaannya, ini lintas platform dan berjalan pada Python 2.4-3.2. Saya mengujinya di Windows, OS X dan Linux.
Versi kode terbaru tersedia singleton.py . Silakan laporkan bug di sini .
Anda dapat menginstal cenderung menggunakan salah satu metode berikut:
easy_install tendo
pip install tendo
sumber
Sederhana,
cross-platformsolusi, ditemukan di pertanyaan lain oleh Zgoda :Sangat mirip dengan saran S. Lott, tetapi dengan kodenya.
sumber
fcntl
modul di Windows (meskipun fungsinya dapat ditiru).fg
. Jadi, sepertinya itu berfungsi dengan benar untuk Anda (yaitu, aplikasi masih aktif, tetapi ditangguhkan, jadi kuncinya tetap di tempatnya).lock_file_pointer = os.open(lock_path, os.O_WRONLY | os.O_CREAT)
Kode ini khusus untuk Linux. Ini menggunakan soket domain UNIX 'abstrak', tetapi sederhana dan tidak akan meninggalkan file kunci basi. Saya lebih suka solusi di atas karena tidak memerlukan port TCP khusus yang dipesan.
String unik
postconnect_gateway_notify_lock
dapat diubah untuk memungkinkan beberapa program yang membutuhkan satu contoh diberlakukan.sumber
Saya tidak tahu apakah itu cukup pythonic, tetapi di dunia Java, mendengarkan pada port yang ditentukan adalah solusi yang cukup banyak digunakan, karena berfungsi pada semua platform utama dan tidak memiliki masalah dengan program yang mogok.
Keuntungan lain dari mendengarkan port adalah Anda dapat mengirim perintah ke instance yang sedang berjalan. Misalnya ketika pengguna memulai program untuk kedua kalinya, Anda dapat mengirimkan perintah yang sedang berjalan untuk memintanya membuka jendela lain (itulah yang dilakukan Firefox, misalnya. Saya tidak tahu apakah mereka menggunakan port TCP atau pipa bernama atau sesuatu seperti itu, ').
sumber
import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.bind(('localhost', DEFINED_PORT))
. SebuahOSError
akan dimunculkan jika proses lain terikat ke port yang sama.Belum pernah menulis python sebelumnya, tetapi inilah yang baru saja saya terapkan di mycheckpoint, untuk mencegahnya dimulai dua kali atau lebih dengan crond:
Menemukan saran Slava-N setelah memposting ini di terbitan lain (http://stackoverflow.com/questions/2959474). Yang ini disebut sebagai fungsi, mengunci file skrip yang sedang dieksekusi (bukan file pid) dan mempertahankan kunci sampai skrip berakhir (normal atau error).
sumber
Gunakan file pid. Anda memiliki beberapa lokasi yang diketahui, "/ path / to / pidfile" dan saat startup Anda melakukan sesuatu seperti ini (sebagian pseudocode karena saya sedang pre-coffee dan tidak ingin bekerja terlalu keras):
Jadi, dengan kata lain, Anda memeriksa apakah pidfile ada; jika tidak, tulis pid Anda ke file itu. Jika pidfile memang ada, maka periksa untuk melihat apakah pid adalah pid dari proses yang sedang berjalan; jika demikian, maka Anda memiliki proses langsung lainnya yang sedang berjalan, jadi matikan saja. Jika tidak, maka proses sebelumnya macet, jadi catatlah, dan kemudian tulis pid Anda sendiri ke file di tempat yang lama. Kemudian lanjutkan.
sumber
Anda sudah menemukan jawaban untuk pertanyaan serupa di utas lain, jadi demi kelengkapan lihat bagaimana mencapai hal yang sama pada Windows uning bernama mutex.
http://code.activestate.com/recipes/474070/
sumber
Ini mungkin berhasil.
Coba buat file PID ke lokasi yang diketahui. Jika Anda gagal, seseorang telah mengunci file, Anda sudah selesai.
Saat Anda selesai secara normal, tutup dan hapus file PID, sehingga orang lain dapat menimpanya.
Anda dapat membungkus program Anda dalam skrip shell yang menghapus file PID bahkan jika program Anda macet.
Anda juga dapat menggunakan file PID untuk mematikan program jika program tersebut hang.
sumber
Menggunakan file kunci adalah pendekatan yang cukup umum pada unix. Jika macet, Anda harus membersihkannya secara manual. Anda dapat menyimpan PID dalam file, dan saat startup memeriksa apakah ada proses dengan PID ini, menimpa file kunci jika tidak. (Namun, Anda juga membutuhkan kunci di sekitar read-file-check-pid-rewrite-file). Anda akan menemukan apa yang Anda butuhkan untuk mendapatkan dan memeriksa pid di os -package. Cara umum untuk memeriksa apakah ada proses dengan pid yang diberikan, adalah mengirimkannya sinyal non-fatal.
Alternatif lain dapat menggabungkan ini dengan semaphores flock atau posix.
Membuka soket jaringan, seperti yang diusulkan saua, mungkin akan menjadi yang termudah dan paling portabel.
sumber
Untuk siapa saja yang menggunakan wxPython untuk aplikasinya, Anda dapat menggunakan fungsi yang
wx.SingleInstanceChecker
didokumentasikan di sini .Saya pribadi menggunakan subclass
wx.App
yang memanfaatkanwx.SingleInstanceChecker
dan mengembalikanFalse
dariOnInit()
jika ada instance aplikasi yang sudah ada yang berjalan seperti ini:Ini adalah pengganti sederhana untuk
wx.App
yang melarang beberapa contoh. Untuk menggunakannya cukup gantiwx.App
denganSingleApp
dalam kode Anda seperti ini:sumber
Berikut adalah solusi khusus Windows saya. Letakkan berikut ini ke dalam modul, mungkin disebut 'onlyone.py', atau apa pun. Sertakan modul itu langsung ke file skrip python __ main __ Anda.
Penjelasan
Kode mencoba membuat mutex dengan nama yang diturunkan dari jalur lengkap ke skrip. Kami menggunakan garis miring ke depan untuk menghindari potensi kebingungan dengan sistem file yang sebenarnya.
Keuntungan
sumber
Solusi terbaik untuk ini di windows adalah dengan menggunakan mutex seperti yang disarankan oleh @zgoda.
Beberapa jawaban menggunakan
fctnl
(termasuk juga dalam paket @sorin tendo) yang tidak tersedia di windows dan jika Anda mencoba untuk membekukan aplikasi python Anda menggunakan paket sepertipyinstaller
yang melakukan impor statis, itu membuat kesalahan.Selain itu, menggunakan metode file kunci, menciptakan
read-only
masalah dengan file database (mengalami ini dengansqlite3
).sumber
Saya memposting ini sebagai jawaban karena saya adalah pengguna baru dan Stack Overflow tidak mengizinkan saya memilih.
Solusi Sorin Sbarnea bekerja untuk saya di bawah OS X, Linux dan Windows, dan saya berterima kasih untuk itu.
Namun, tempfile.gettempdir () berperilaku satu cara di bawah OS X dan Windows dan yang lain di bawah beberapa / banyak / semua (?) * Nixes (mengabaikan fakta bahwa OS X juga Unix!). Perbedaannya penting untuk kode ini.
OS X dan Windows memiliki direktori temporer khusus pengguna, jadi file temporer yang dibuat oleh satu pengguna tidak terlihat oleh pengguna lain. Sebaliknya, di bawah banyak versi * nix (saya menguji Ubuntu 9, RHEL 5, OpenSolaris 2008 dan FreeBSD 8), temp dirnya adalah / tmp untuk semua pengguna.
Artinya, saat lockfile dibuat di mesin multi-pengguna, lockfile dibuat di / tmp dan hanya pengguna yang membuat lockfile pertama kali yang dapat menjalankan aplikasi.
Solusi yang mungkin adalah menyematkan nama pengguna saat ini di nama file kunci.
Perlu dicatat bahwa solusi OP untuk mengambil port juga akan berperilaku buruk pada mesin multi-pengguna.
sumber
Saya gunakan
single_process
di gentoo saya;contoh :
lihat: https://pypi.python.org/pypi/single_process/1.0
sumber
Saya terus curiga seharusnya ada solusi POSIXy yang baik menggunakan grup proses, tanpa harus menekan sistem file, tetapi saya tidak bisa memahaminya. Sesuatu seperti:
Saat memulai, proses Anda mengirimkan 'kill -0' ke semua proses dalam grup tertentu. Jika ada proses seperti itu, itu keluar. Kemudian ia bergabung dengan grup. Tidak ada proses lain yang menggunakan grup itu.
Namun, ini memiliki syarat perlombaan - beberapa proses dapat melakukannya pada waktu yang sama dan semuanya berakhir dengan bergabung ke grup dan berjalan secara bersamaan. Pada saat Anda telah menambahkan semacam mutex untuk membuatnya kedap air, Anda tidak lagi memerlukan grup proses.
Ini mungkin dapat diterima jika proses Anda hanya dimulai dengan cron, sekali setiap menit atau setiap jam, tetapi itu membuat saya sedikit gugup karena akan salah tepat pada hari ketika Anda tidak menginginkannya.
Saya kira ini bukan solusi yang sangat baik, kecuali seseorang dapat memperbaikinya?
sumber
Saya mengalami masalah ini minggu lalu, dan meskipun saya menemukan beberapa solusi yang baik, saya memutuskan untuk membuat paket python yang sangat sederhana dan bersih dan mengunggahnya ke PyPI. Ini berbeda dari tendo karena dapat mengunci nama sumber daya string apa pun. Meskipun Anda pasti bisa mengunci
__file__
untuk mendapatkan efek yang sama.Instal dengan:
pip install quicklock
Menggunakannya sangat sederhana:
Lihat: https://pypi.python.org/pypi/quicklock
sumber
Berdasarkan jawaban Roberto Rosario, saya menemukan fungsi berikut:
Kita perlu mendefinisikan global
SOCKET
vaiable karena ini hanya akan menjadi sampah yang dikumpulkan ketika seluruh proses berhenti. Jika kita mendeklarasikan variabel lokal dalam fungsinya, itu akan keluar dari ruang lingkup setelah fungsi keluar, sehingga soket dihapus.Semua pujian harus diberikan kepada Roberto Rosario, karena saya hanya mengklarifikasi dan menguraikan kodenya. Dan kode ini hanya akan berfungsi di Linux, seperti yang dijelaskan teks yang dikutip berikut dari https://troydhanson.github.io/network/Unix_domain_sockets.html :
sumber
contoh linux
Metode ini didasarkan pada pembuatan file sementara yang otomatis dihapus setelah Anda menutup aplikasi. peluncuran program kami memverifikasi keberadaan file; jika file ada (ada eksekusi yang tertunda), program ditutup; jika tidak, ia membuat file dan melanjutkan eksekusi program.
sumber
Pada sistem Linux, seseorang juga dapat menanyakan
pgrep -a
jumlah instance, skrip ditemukan dalam daftar proses (opsi -a mengungkapkan string baris perintah lengkap). MisalnyaHapus
-u $UID
jika batasan berlaku untuk semua pengguna. Penafian: a) diasumsikan bahwa nama skrip (basis) unik, b) mungkin ada kondisi balapan.sumber
sumber