Làm thế nào để kết thúc một luồng khi chương trình chính kết thúc?


85

Nếu tôi có một chuỗi trong một vòng lặp vô hạn, có cách nào để kết thúc nó khi chương trình chính kết thúc (ví dụ: khi tôi nhấn Ctrl+ C) không?

Câu trả lời:


46

Kiểm tra câu hỏi này. Câu trả lời đúng có lời giải thích tuyệt vời về cách kết thúc luồng đúng cách: Có cách nào để giết một luồng trong Python không?

Để làm cho chuỗi dừng trên tín hiệu Ngắt bàn phím (ctrl + c), bạn có thể bắt ngoại lệ "KeyboardInterrupt" và dọn dẹp trước khi thoát. Như thế này:

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

Bằng cách này, bạn có thể kiểm soát những việc cần làm bất cứ khi nào chương trình bị chấm dứt đột ngột.

Bạn cũng có thể sử dụng mô-đun tín hiệu tích hợp cho phép bạn thiết lập bộ xử lý tín hiệu (trong trường hợp cụ thể của bạn là tín hiệu SIGINT): http://docs.python.org/library/signal.html


Cảm ơn rất nhiều cho trả lời của bạn. Tôi có thể đã không nêu câu hỏi một cách chính xác. Trong ví dụ được đưa ra trong câu hỏi đó, vẫn cần thực hiện hàm stop () của luồng. Khi tôi kết thúc chương trình một cách bất thường bằng ctrl + C, điều đó không thể xảy ra. Vì vậy, câu hỏi của tôi hơi giống như "làm cách nào để gọi hàm mythread.stop () nếu luồng chính bị gián đoạn"
facha

1
cleanup_stop_thread()một chức năng toàn cục mà tôi có thể sử dụng? hay tôi cần phải thực hiện nó?
alper

@alper, tôi nghĩ có lẽ đó chỉ là một ví dụ có thể triển khai một cái gì đó. Bạn nên thực hiện điều đó
Leonardo Rick

98

Nếu bạn tạo luồng công nhân của mình là các luồng daemon, chúng sẽ chết khi tất cả các luồng không phải là daemon của bạn (ví dụ: luồng chính) đã thoát.

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


4
Cảm ơn câu trả lời đơn giản và chính xác, trạng thái daemon threading.Thread mặc định isDaemon()là False, hãy đặt nó là True setDaemon(True).
Tong

3
Điều này trả lời câu hỏi và chỉ hoạt động. Nói chung, op không hỏi làm thế nào để thoát khỏi chuỗi một cách rõ ràng.
Johannes Overmann

1
isDaemon()setDaemon()đang thu khí cũ / setters (theo doc liên kết ở trên), chỉ cần sử dụng daemon=Truetrongthreading.Thread()
fabio.sang

1
Lưu ý rằng việc sử dụng các chuỗi daemon có thể gây ra các vấn đề khác và có thể không phải là những gì bạn muốn ở đây: stackoverflow.com/questions/20596918/…
Doopy

Để tránh sử dụng các chuỗi daemon và giết sạch các chuỗi, hãy xem stackoverflow.com/questions/58910372/…
Pat-Laugh

14

Thử kích hoạt tiểu trình dưới dạng daemon-thread.

Ví dụ:

Khuyến nghị:

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()

Nội tuyến:

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

API cũ:

t.setDaemon(True)
t.start()

Khi luồng chính của bạn kết thúc ("tức là khi tôi nhấn Ctrl+ C"), các luồng khác cũng sẽ bị giết theo hướng dẫn ở trên.


1
Lưu ý rằng việc sử dụng các chuỗi daemon có thể gây ra các vấn đề khác và có thể không phải là những gì bạn muốn ở đây: stackoverflow.com/questions/20596918/…
Doopy

12

Sử dụng mô-đun atexit của thư viện tiêu chuẩn của Python để đăng ký các hàm "kết thúc" được gọi (trên luồng chính) trên bất kỳ kết thúc "sạch" hợp lý nào của luồng chính, bao gồm một ngoại lệ không cần thiết, chẳng hạn như KeyboardInterrupt. Các hàm kết thúc như vậy có thể (mặc dù không thể tránh khỏi trong chuỗi chính!) Gọi bất kỳ stophàm nào bạn yêu cầu; cùng với khả năng thiết lập một chủ đề daemon, cung cấp cho bạn các công cụ để thiết kế đúng chức năng hệ thống mà bạn cần.


Lưu ý rằng phương pháp này hoạt động mà không yêu cầu các chuỗi được daemonized trong các phiên bản Python trước 2.6.5, hãy xem câu trả lời cho stackoverflow.com/questions/3713360/… . Đây là IMHO đáng tiếc, vì các chuỗi daemon trong quá trình tắt máy có một chút lộn xộn trước python 3.4 ( bug.python.org/issue19466 ). Nếu bạn dừng lại tham gia các chuỗi daemon của mình trong các trình xử lý atexit của mình, tất cả đều ổn, với chi phí (có thể là không đáng kể) của việc tuần tự hóa chuỗi xé nhỏ.
NeilenMarais

Hãy lưu ý rằng những điều kỳ lạ có thể xảy ra do các atexit.register()lệnh gọi sau khi thực hiện trong mô-đun Python, khiến thủ tục kết thúc của bạn được thực thi sau lệnh multiprocessinggọi. Tôi gặp sự cố này khi xử lý Queuedaemonchủ đề: “Lỗi EOF” khi thoát chương trình bằng cách sử dụng Hàng đợi và Luồng đa xử lý .
Delgan

Rõ ràng trong các phiên bản Python hiện đại, chẳng hạn như 3.7.4+, các atexittrình xử lý không được gọi khi các luồng không phải daemon còn sống và luồng chính thoát. Xem Tập lệnh bị kẹt khi thoát khi sử dụng atexit để kết thúc chuỗi .
martineau

9

Nếu bạn sinh ra một Chủ đề như vậy - myThread = Thread(target = function)- và sau đó làm myThread.start(); myThread.join(). Khi CTRL-C được bắt đầu, luồng chính sẽ không thoát vì nó đang chờ myThread.join()lệnh gọi chặn đó . Để khắc phục điều này, chỉ cần đặt thời gian chờ cho cuộc gọi .join (). Thời gian chờ có thể kéo dài như bạn muốn. Nếu bạn muốn nó đợi vô thời hạn, chỉ cần đặt một khoảng thời gian chờ thực sự dài, chẳng hạn như 99999. Bạn cũng nên làm myThread.daemon = Truenhư vậy tất cả các luồng sẽ thoát khi luồng chính (không phải daemon) thoát.


myThread.daemon = Truelà một giải pháp tuyệt vời cho vấn đề này.
Brannon

5
@Brannon .daemon=Truekhông phải là dung dịch rắn. Kiểm tra chủ đề này cho một lời giải thích: stackoverflow.com/a/20598791/5562492
Odyssee

2

Các luồng daemon bị giết một cách không theo quy định nên mọi hướng dẫn của trình hoàn thiện đều không được thực thi. Một giải pháp khả thi là kiểm tra xem luồng chính có còn sống hay không thay vì vòng lặp vô hạn.

Ví dụ: đối với Python 3:

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

Xem Kiểm tra xem Chủ đề chính có còn tồn tại từ một chủ đề khác không .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.