ฉันมีสคริปต์ python ที่ใช้เธรดและส่งคำขอ HTTP จำนวนมาก ฉันคิดว่าสิ่งที่เกิดขึ้นคือในขณะที่คำขอ HTTP (โดยใช้ urllib2) กำลังอ่านมันถูกบล็อกและไม่ตอบสนองต่อCtrlCการหยุดโปรแกรม มีวิธีแก้ปัญหานี้หรือไม่?
ฉันมีสคริปต์ python ที่ใช้เธรดและส่งคำขอ HTTP จำนวนมาก ฉันคิดว่าสิ่งที่เกิดขึ้นคือในขณะที่คำขอ HTTP (โดยใช้ urllib2) กำลังอ่านมันถูกบล็อกและไม่ตอบสนองต่อCtrlCการหยุดโปรแกรม มีวิธีแก้ปัญหานี้หรือไม่?
คำตอบ:
บน Windows, CtrlBreakวิธีเดียวที่แน่ใจคือการใช้ หยุดทุกสคริปต์ python ทันที!
(โปรดทราบว่าในแป้นพิมพ์บางรุ่นจะมีป้ายกำกับ "Break" เป็น "Pause")
Break
? ฉันจะพิมพ์ได้อย่างไร?
การกดCtrl+ cในขณะที่โปรแกรม python กำลังทำงานจะทำให้ python เพิ่มKeyboardInterrupt
ข้อยกเว้น เป็นไปได้ว่าโปรแกรมที่สร้างคำขอ HTTP จำนวนมากจะมีรหัสการจัดการข้อยกเว้นจำนวนมาก หากexcept
ส่วนของtry
- except
บล็อกไม่ได้ระบุข้อยกเว้นที่ควรจับมันจะจับข้อยกเว้นทั้งหมดรวมถึงKeyboardInterrupt
ที่คุณเพิ่งก่อ โปรแกรม python ที่เข้ารหัสอย่างถูกต้องจะใช้ประโยชน์จากไฟล์ลำดับชั้นหลามข้อยกเว้นException
และมีเพียงจับข้อยกเว้นที่มาจาก
#This is the wrong way to do things
try:
#Some stuff might raise an IO exception
except:
#Code that ignores errors
#This is the right way to do things
try:
#Some stuff might raise an IO exception
except Exception:
#This won't catch KeyboardInterrupt
หากคุณไม่สามารถเปลี่ยนรหัสได้ (หรือต้องการฆ่าโปรแกรมเพื่อให้การเปลี่ยนแปลงของคุณมีผล) คุณสามารถลองกดCtrl+ cอย่างรวดเร็ว KeyboardInterrupt
ข้อยกเว้นประการแรกจะทำให้โปรแกรมของคุณหลุดออกจากtry
บล็อกและหวังว่าKeyboardInterrupt
จะมีการยกข้อยกเว้นอย่างใดอย่างหนึ่งในภายหลังเมื่อโปรแกรมอยู่นอกtry
บล็อก
หากรันใน Python shell ให้ใช้Ctrl+ Zมิฉะนั้นให้ค้นหาpython
กระบวนการและฆ่ามัน
^Z
-> [1]+ Stopped
-> kill %1
หยุดงาน # 1 (หรืองาน% 1 ตามที่ bash วางไว้)
fg
จะนำมันกลับมา
Ctrl+Z
ไม่ใช่วิธีที่เหมาะสมในการหยุดสคริปต์ python และควรหลีกเลี่ยงเว้นแต่คุณจะวางแผนที่จะดำเนินการต่อกระบวนการที่หยุดชั่วคราว
กระบวนการขัดจังหวะขึ้นอยู่กับฮาร์ดแวร์และระบบปฏิบัติการ ดังนั้นคุณจะมีพฤติกรรมที่แตกต่างกันมากขึ้นอยู่กับตำแหน่งที่คุณรันสคริปต์ python ตัวอย่างเช่นบนเครื่อง Windows เรามีCtrl+ C( SIGINT
) และCtrl+ Break(SIGBREAK
)
ดังนั้นในขณะที่ SIGINT มีอยู่ในทุกระบบและสามารถจัดการและจับสัญญาณได้ แต่สัญญาณ SIGBREAK จะเป็นเฉพาะ Windows (และสามารถปิดใช้งานได้ในCONFIG.SYS ) และได้รับการจัดการโดย BIOS เป็นเวกเตอร์ขัดจังหวะINT 1Bhซึ่งเป็นสาเหตุที่ทำให้คีย์นี้ มีพลังมากกว่าที่อื่น ๆ ดังนั้นหากคุณใช้ระบบปฏิบัติการที่มีการปรุงแต่ง * nix คุณจะได้ผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับการใช้งานเนื่องจากสัญญาณนั้นไม่มีอยู่ที่นั่น แต่มีสัญญาณอื่น ๆ ใน Linux คุณสามารถตรวจสอบว่ามีสัญญาณอะไรบ้างโดย:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGEMT 8) SIGFPE 9) SIGKILL 10) SIGBUS
11) SIGSEGV 12) SIGSYS 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGURG 17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGPWR 30) SIGUSR1
31) SIGUSR2 32) SIGRTMAX
ดังนั้นหากคุณต้องการจับCTRL+BREAK
สัญญาณบนระบบ linux คุณจะต้องตรวจสอบว่าสัญญาณ POSIXใดที่พวกเขาแมปคีย์นั้น การแมปยอดนิยม ได้แก่
CTRL+\ = SIGQUIT
CTRL+D = SIGQUIT
CTRL+C = SIGINT
CTRL+Z = SIGTSTOP
CTRL+BREAK = SIGKILL or SIGTERM or SIGSTOP
ในความเป็นจริงมีฟังก์ชั่นอื่น ๆ อีกมากมายใน Linux ซึ่งSysRqคีย์ (System Request) สามารถใช้ชีวิตของมันเอง ...
โพสต์นี้เก่า แต่เมื่อเร็ว ๆ นี้ฉันพบปัญหาเดียวกันของCtrl+ Cไม่ยุติสคริปต์ Python บน Linux ฉันใช้Ctrl+ \( SIGQUIT
)
Ctrl+Dความแตกต่างสำหรับ Windows และ Linux
ปรากฎว่าใน Python 3.6 ตัวแปล Python จัดการCtrl+ Cต่างกันสำหรับ Linux และ Windows สำหรับ Linux Ctrl+ Cจะทำงานได้ตามที่คาดไว้เป็นส่วนใหญ่อย่างไรก็ตามใน Windows Ctrl+ C ส่วนใหญ่จะไม่ทำงานโดยเฉพาะอย่างยิ่งหาก Python กำลังเรียกใช้การบล็อกการโทรเช่นthread.join
หรือรอการตอบกลับทางเว็บ อย่างไรก็ตามมันใช้งานtime.sleep
ได้ นี่คือคำอธิบายที่ดีเกี่ยวกับสิ่งที่เกิดขึ้นในล่าม Python สังเกตว่าCtrl+ Cสร้างSIGINT
สร้าง
โซลูชันที่ 1: ใช้Ctrl+ Breakหรือเทียบเท่า
ใช้แป้นพิมพ์ลัดด้านล่างในหน้าต่างเทอร์มินัล / คอนโซลซึ่งจะสร้างSIGBREAK
ที่ระดับต่ำกว่าใน OS และยุติการแปล Python
Mac OS และ Linux
Ctrl+ Shift+ \หรือCtrl+\
Windows :
โซลูชันที่ 2: ใช้ Windows API
ด้านล่างนี้เป็นฟังก์ชันที่มีประโยชน์ซึ่งจะตรวจจับ Windows และติดตั้งตัวจัดการแบบกำหนดเองสำหรับCtrl+ Cในคอนโซล:
#win_ctrl_c.py
import sys
def handler(a,b=None):
sys.exit(1)
def install_handler():
if sys.platform == "win32":
import win32api
win32api.SetConsoleCtrlHandler(handler, True)
คุณสามารถใช้ด้านบนดังนี้:
import threading
import time
import win_ctrl_c
# do something that will block
def work():
time.sleep(10000)
t = threading.Thread(target=work)
t.daemon = True
t.start()
#install handler
install_handler()
# now block
t.join()
#Ctrl+C works now!
แนวทางที่ 3: วิธีการสำรวจความคิดเห็น
ฉันไม่ชอบหรือแนะนำวิธีนี้เพราะใช้โปรเซสเซอร์และพลังงานโดยไม่จำเป็นส่งผลเสียต่อประสิทธิภาพ
เวลานำเข้าเธรดการนำเข้า
def work():
time.sleep(10000)
t = threading.Thread(target=work)
t.daemon = True
t.start()
while(True):
t.join(0.1) #100ms ~ typical human response
# you will get KeyboardIntrupt exception
ctrl + c
จะไม่ออก แต่แสดงKeyboardInterrupt
ขึ้น
บน Mac กดCtrl+ \เพื่อออกจากกระบวนการ python ที่เชื่อมต่อกับเทอร์มินัล
บน Mac / in Terminal:
สิ่งเหล่านี้อาจช่วยได้
คุณสามารถเปิดตัวจัดการงานของคุณ (ctrl + alt + delete จากนั้นไปที่ตัวจัดการงาน) และมองหา python และเซิร์ฟเวอร์ถูกเรียก (เช่นตัวอย่าง) _go_app (หลักการตั้งชื่อคือ: _language_app)
ถ้าฉันจบงาน _go_app มันจะจบเซิร์ฟเวอร์ดังนั้นเมื่อไปที่นั่นในเบราว์เซอร์จะบอกว่า "จบลงโดยไม่คาดคิด" ฉันใช้ git bash ด้วยและเมื่อฉันเริ่มเซิร์ฟเวอร์ฉันไม่สามารถแยกออกจากเซิร์ฟเวอร์ในเชลล์ของ bash ได้ ด้วย ctrl + c หรือ ctrl + pause แต่เมื่อคุณจบงาน python (งานที่ใช้ 63.7 mb) มันจะแยกสคริปต์เซิร์ฟเวอร์ออกเป็น bash และอนุญาตให้ฉันใช้ git bash shell
สำหรับบันทึกสิ่งที่ฆ่ากระบวนการบนของราสเบอร์รี่ 3B + (วิ่ง raspbian) เป็น+Ctrl 'บนแป้นพิมพ์ AZERTY ภาษาฝรั่งเศสของฉันการสัมผัส'ยังเป็นเลข 4