Python betiği Ctrl-C ile öldürülemez


117

Python iş parçacığını aşağıdaki komut dosyasıyla test ediyorum:

import threading

class FirstThread (threading.Thread):
    def run (self):
        while True:
            print 'first'

class SecondThread (threading.Thread):
    def run (self):
        while True:
            print 'second'

FirstThread().start()
SecondThread().start()

Bu, Kubuntu 11.10 üzerinde Python 2.7'de çalışıyor. Ctrl+ Conu öldürmeyecek. Ayrıca sistem sinyalleri için bir işleyici eklemeyi denedim, ancak bu yardımcı olmadı:

import signal 
import sys
def signal_handler(signal, frame):
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

İşlemi sonlandırmak için programı Ctrl+ ile arka plana gönderdikten sonra PID ile öldürüyorum ki bu Zgöz ardı edilmiyor. Ctrl+ Neden Cbu kadar ısrarla göz ardı ediliyor? Bunu nasıl çözebilirim?


@dotancohen Windows'ta çalışıyor mu?
kiriloff

@vitaibian: Windows üzerinde test etmedim, ancak işletim sistemine özgü değil gibi görünüyor.
dotancohen

Yanıtlar:


178

Ctrl+ Cana iş parçacığını sonlandırır, ancak iş parçacıklarınız arka plan programı modunda olmadığı için çalışmaya devam ederler ve bu da süreci canlı tutar. Onları cinler yapabiliriz:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

Ama sonra başka bir sorun var - ana iş parçacığı iş parçacıklarınızı başlattıktan sonra, yapacak başka bir şey yok. Böylece çıkar ve ipler anında yok edilir. Öyleyse ana konuyu canlı tutalım:

import time
while True:
    time.sleep(1)

Şimdi, siz Ctrl+ 'ya basana kadar' ilk 've' ikinci 'yazdırmaya devam edecek C.

Düzenleme: yorum yapanların da belirttiği gibi, arka plan programı iş parçacıklarının geçici dosyalar gibi şeyleri temizleme şansı olmayabilir. Buna ihtiyacınız varsa KeyboardInterrupt, ana iş parçacığını yakalayın ve temizleme ve kapatmayı koordine etmesini sağlayın. Ancak çoğu durumda, arka plan programı iş parçacıklarının aniden ölmesine izin vermek muhtemelen yeterince iyidir.


6
Bu konuları yaparak nazikçe durdurulmadığını ve bazı kaynakların serbest bırakılmadığını belirtmelisiniz.
Tommaso Barbugli

1
Ctrl-C hiçbir zaman hiçbir şeyi durdurmanın zarif bir yolu değildir. Hangi kaynakların bırakılacağından emin değilim - işletim sistemi işlem çıktığında herhangi bir şey talep etmemeli mi?
Thomas K

7
@ThomasK tarafından oluşturulan geçici dosyalar tempfile.TemporaryFile()diskte bırakılabilir, örneğin.
Feuermurmel

1
@ deed02392: Ana iş parçacığına tam olarak ne olduğunu bilmiyorum, ama bildiğim kadarıyla çıktıktan sonra onunla hiçbir şey yapamazsınız. Tüm arka plan programı olmayan iş parçacıkları bittiğinde süreç biter; ebeveyn-çocuk ilişkileri buna girmez.
Thomas K

4
Python3 gibi görünüyor geçilmesinin mümkündaemon=True içinThread.__init__
Ryan Haining


3

Onların ölmesini beklediğinizde ileti dizilerinize join () demenin en iyisi olduğunu düşünüyorum. Döngüleri sona erdirmek için kodunuzla biraz özgürlük aldım (oraya da temizleme gereksinimlerini ekleyebilirsiniz). Değişken kalıp her geçişte doğruluk açısından kontrol edilir ve True olduğunda program çıkar.

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()

while Trueaptalca, joindoğrudan yapmalısınız - ve bu geçersiz kılma işlevi biraz sorgulanabilir. Belki de def join(self, force=False): if force: self.die = Truebu onları öldürerek join()değişmez join(force=True). Ancak o zaman bile, herhangi birine katılmadan önce her iki konuyu da bilgilendirmek daha iyidir .
o11c

0

@Thomas K'nin cevabının geliştirilmiş bir versiyonu:

  • Bu özeis_any_thread_alive() göre , otomatik olarak sonlandırabilen bir asistan işlevi tanımlamak .main()

Örnek kodlar:

import threading

def job1():
    ...

def job2():
    ...

def is_any_thread_alive(threads):
    return True in [t.is_alive() for t in threads]

if __name__ == "__main__":
    ...
    t1 = threading.Thread(target=job1,daemon=True)
    t2 = threading.Thread(target=job2,daemon=True)
    t1.start()
    t2.start()

    while is_any_thread_alive([t1,t2]):
        time.sleep(0)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.