จะยุติเธรดเมื่อโปรแกรมหลักสิ้นสุดได้อย่างไร?


86

ถ้าฉันมีเธรดในการวนซ้ำแบบไม่มีที่สิ้นสุดจะมีวิธียุติเธรดเมื่อโปรแกรมหลักสิ้นสุดลงหรือไม่ (เช่นเมื่อฉันกดCtrl+ C)

คำตอบ:


46

ตรวจสอบคำถามนี้ คำตอบที่ถูกต้องมีคำอธิบายที่ดีในการยุติเธรดอย่างถูกวิธี: มีวิธีใดในการฆ่าเธรดใน Python หรือไม่?

เพื่อให้เธรดหยุดบนสัญญาณ Keyboard Interrupt (ctrl + c) คุณสามารถตรวจจับข้อยกเว้น "KeyboardInterrupt" และล้างข้อมูลก่อนออกได้ แบบนี้:

try:
    start_thread()  
except (KeyboardInterrupt, SystemExit):
    cleanup_stop_thread()
    sys.exit()

ด้วยวิธีนี้คุณสามารถควบคุมสิ่งที่ต้องทำเมื่อใดก็ตามที่โปรแกรมถูกยกเลิกทันที

คุณยังสามารถใช้โมดูลสัญญาณในตัวที่ให้คุณตั้งค่าตัวจัดการสัญญาณ (ในกรณีเฉพาะของคุณคือสัญญาณ SIGINT): http://docs.python.org/library/signal.html


ขอบคุณมากสำหรับการตอบกลับของคุณ ฉันอาจระบุคำถามไม่ถูกต้อง ในตัวอย่างที่ให้ไว้ในคำถามนั้นจำเป็นต้องเรียกใช้ฟังก์ชัน stop () ของเธรด เมื่อฉันยุติโปรแกรมอย่างผิดปกติโดย ctrl + C สิ่งนั้นจะไม่เกิดขึ้น ดังนั้นคำถามของฉันก็ประมาณว่า "ฉันจะเรียกว่า Mythread.stop () funcion ได้อย่างไรหากการไหลของเธรดหลักถูกขัดจังหวะ"
facha

1
คือcleanup_stop_thread()ฟังก์ชั่นระดับโลกที่ฉันสามารถใช้? หรือฉันควรจะใช้มัน?
Alper

@alper ฉันคิดว่ามันอาจจะเป็นแค่ตัวอย่างที่เป็นไปได้ในการนำบางสิ่งไปใช้ คุณควรนำไปใช้
Leonardo Rick

100

หากคุณสร้างเธรด daemon เธรดผู้ปฏิบัติงานของคุณเธรดจะตายเมื่อเธรดที่ไม่ใช่ daemon ทั้งหมดของคุณออกจากเธรดหลัก (เช่นเธรดหลัก)

http://docs.python.org/library/threading.html#threading.Thread.daemon


4
ขอบคุณสำหรับคำตอบที่ง่ายและแม่นยำเริ่มต้น threading.Thread สถานะภูตisDaemon()คือ False setDaemon(True)ตั้งทรูโดย
ตอง

3
สิ่งนี้ตอบคำถามและใช้งานได้จริง op ไม่ได้ถามวิธีการออกจากเธรดโดยทั่วไปอย่างหมดจด
Johannes Overmann

1
isDaemon()และsetDaemon()เป็น getters / setters เก่า (ตามเอกสารที่เชื่อมโยงด้านบน) เพียงใช้daemon=Trueในthreading.Thread()
fabio.sang

1
โปรดทราบว่าการใช้เธรด daemon อาจทำให้เกิดปัญหาอื่น ๆ และอาจไม่ใช่สิ่งที่คุณต้องการที่นี่: stackoverflow.com/questions/20596918/…
Doopy

เพื่อหลีกเลี่ยงการใช้เธรด daemon และฆ่าเธรดอย่างหมดจดโปรดดูstackoverflow.com/questions/58910372/…
ผู้ใช้

15

ลองเปิดใช้งานเธรดย่อยเป็น daemon-thread

สำหรับอินสแตนซ์:

แนะนำ:

from threading import Thread

t = Thread(target=<your-method>)
t.daemon = True  # This thread dies when main thread (only non-daemon thread) exits.
t.start()

อินไลน์:

t = Thread(target=<your-method>, daemon=True).start()

API เก่า:

t.setDaemon(True)
t.start()

เมื่อเธรดหลักของคุณสิ้นสุด ("เช่นเมื่อฉันกดCtrl+ C") เธรดอื่น ๆ จะถูกฆ่าโดยคำแนะนำข้างต้น


1
โปรดทราบว่าการใช้เธรด daemon อาจทำให้เกิดปัญหาอื่น ๆ และอาจไม่ใช่สิ่งที่คุณต้องการที่นี่: stackoverflow.com/questions/20596918/…
Doopy

12

ใช้โมดูลatexitของไลบรารีมาตรฐานของ Python เพื่อลงทะเบียนฟังก์ชัน "การสิ้นสุด" ที่เรียก (บนเธรดหลัก) ในการยุติเธรดหลักที่ "สะอาด" อย่างสมเหตุสมผลรวมถึงข้อยกเว้นที่ไม่ถูกจับเช่นKeyboardInterrupt. ฟังก์ชันการสิ้นสุดดังกล่าวอาจ (แม้ว่าจะหลีกเลี่ยงไม่ได้ในเธรดหลัก!) เรียกใช้stopฟังก์ชันใด ๆ ที่คุณต้องการ พร้อมกับความเป็นไปได้ในการตั้งเธรดเป็นdaemonซึ่งจะช่วยให้คุณมีเครื่องมือในการออกแบบฟังก์ชันการทำงานของระบบที่คุณต้องการ


โปรดทราบว่าวิธีการนี้ทำงานโดยไม่ต้องมีหัวข้อ daemonized ในรุ่น Python 2.6.5 ก่อนที่จะดูคำตอบstackoverflow.com/questions/3713360/... นี่เป็น IMHO ที่โชคร้ายเนื่องจากเธรด daemon ในระหว่างการปิดระบบจะค่อนข้างยุ่งก่อน python 3.4 ( bugs.python.org/issue19466 ) หากคุณหยุดและเข้าร่วมเธรด daemon ของคุณในตัวจัดการ atexit ของคุณทุกอย่างจะดีโดยที่ต้นทุน (อาจไม่สำคัญ) ในการทำให้เธรดของคุณเป็นอนุกรม
NeilenMarais

โปรดทราบว่าสิ่งแปลก ๆ อาจเกิดขึ้นได้เนื่องจากการatexit.register()โทรที่โพสต์ในโมดูล Python ทำให้ขั้นตอนการยกเลิกของคุณถูกดำเนินการหลังจากขั้นตอนmultiprocessingหนึ่ง ผมทำงานในปัญหานี้จัดการกับQueueและdaemonหัวข้อ: ข้อผิดพลาด“EOF” ที่ออกจากโปรแกรมโดยใช้ multiprocessing คิวและด้าย
Delgan

เห็นได้ชัดว่าใน Python เวอร์ชันใหม่ ๆ เช่น 3.7.4+ ตัวatexitจัดการจะไม่ถูกเรียกเมื่อเธรดที่ไม่ใช่ daemon ยังมีชีวิตอยู่และเธรดหลักจะออก ดูสคริปต์ติดอยู่บนทางออกเมื่อใช้ atexit จะยุติหัวข้อ
martineau

9

หากคุณวางไข่กระทู้เช่นดังนั้น - myThread = Thread(target = function)- myThread.start(); myThread.join()แล้วทำ เมื่อ CTRL-C เริ่มต้นเธรดหลักจะไม่ออกเนื่องจากกำลังรอการmyThread.join()โทรที่บล็อกนั้น ในการแก้ไขปัญหานี้เพียงแค่ใส่การหมดเวลาในการโทร. เข้าร่วม () การหมดเวลาอาจนานเท่าที่คุณต้องการ หากคุณต้องการให้รออย่างไม่มีกำหนดให้ใส่ช่วงหมดเวลาที่ยาวนานจริงๆเช่น 99999 วิธีปฏิบัติที่ดีคือmyThread.daemon = Trueให้เธรดทั้งหมดออกเมื่อเธรดหลัก (ที่ไม่ใช่ดีมอน) ออก


myThread.daemon = Trueเป็นวิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับปัญหานี้
Brannon

5
@ แบรนนอน.daemon=Trueไม่ใช่ทางออกที่มั่นคง ดูคำอธิบายในเธรดนี้: stackoverflow.com/a/20598791/5562492
Odyssee

2

เธรด Daemon ถูกฆ่าอย่างไม่สมศักดิ์ศรีดังนั้นคำสั่ง Finalizer จะไม่ถูกดำเนินการ วิธีแก้ไขที่เป็นไปได้คือการตรวจสอบว่าเธรดหลักยังมีชีวิตอยู่แทนที่จะเป็นลูปที่ไม่มีที่สิ้นสุด

เช่น Python 3:

while threading.main_thread().isAlive():
    do.you.subthread.thing()
gracefully.close.the.thread()

ดูตรวจสอบว่าเธรดหลักยังมีชีวิตอยู่จากเธรดอื่นหรือไม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.