日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)Python教程:signal—-設(shè)置異步事件處理程序

signal —- 設(shè)置異步事件處理程序


該模塊提供了在 python 中使用信號處理程序的機(jī)制。

創(chuàng)新互聯(lián)建站2013年至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢想脫穎而出為使命,1280元弋陽做網(wǎng)站,已為上家服務(wù),為弋陽各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220

一般規(guī)則

signal.signal() 函數(shù)允許定義在接收到信號時(shí)執(zhí)行的自定義處理程序。少量的默認(rèn)處理程序已經(jīng)設(shè)置: SIGPIPE 被忽略(因此管道和套接字上的寫入錯(cuò)誤可以報(bào)告為普通的 Python 異常)以及如果父進(jìn)程沒有更改 SIGINT ,則其會(huì)被翻譯成 KeyboardInterrupt 異常。

一旦設(shè)置,特定信號的處理程序?qū)⒈3职惭b,直到它被顯式重置( Python 模擬 BSD 樣式接口而不管底層實(shí)現(xiàn)),但 SIGCHLD 的處理程序除外,它遵循底層實(shí)現(xiàn)。

On WebAssembly platforms wasm32-emscripten and wasm32-wasi, signals are emulated and therefore behave differently. Several functions and signals are not available on these platforms.

執(zhí)行 Python 信號處理程序

Python 信號處理程序不會(huì)在低級( C )信號處理程序中執(zhí)行。相反,低級信號處理程序設(shè)置一個(gè)標(biāo)志,告訴 virtual machine 稍后執(zhí)行相應(yīng)的 Python 信號處理程序(例如在下一個(gè) bytecode 指令)。這會(huì)導(dǎo)致:

  • 捕獲同步錯(cuò)誤是沒有意義的,例如 SIGFPE 或 SIGSEGV ,它們是由 C 代碼中的無效操作引起的。Python 將從信號處理程序返回到 C 代碼,這可能會(huì)再次引發(fā)相同的信號,導(dǎo)致 Python 顯然的掛起。 從Python 3.3開始,你可以使用 faulthandler 模塊來報(bào)告同步錯(cuò)誤。

  • 純 C 中實(shí)現(xiàn)的長時(shí)間運(yùn)行的計(jì)算(例如在大量文本上的正則表達(dá)式匹配)可以在任意時(shí)間內(nèi)不間斷地運(yùn)行,而不管接收到任何信號。計(jì)算完成后將調(diào)用 Python 信號處理程序。

  • 如果處理句柄引發(fā)了異常,它將在主線程中“憑空”被引發(fā)。 請參閱 下面的注釋 討論相關(guān)細(xì)節(jié)。

信號與線程

Python 信號處理程序總是會(huì)在主 Python 主解釋器的主線程中執(zhí)行,即使信號是在另一個(gè)線程中接收的。 這意味著信號不能被用作線程間通信的手段。 你可以改用 threading 模塊中的同步原語。

此外,只有主解釋器的主線程才被允許設(shè)置新的信號處理程序。

模塊內(nèi)容

在 3.5 版更改: signal (SIG*), handler (SIG_DFL, SIG_IGN) and sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) related constants listed below were turned into enums (Signals, Handlers and Sigmasks respectively). getsignal(), pthread_sigmask(), sigpending() and sigwait() functions return human-readable enums as Signals objects.

The signal module defines three enums:

class signal.Signals

enum.IntEnum collection of SIG* constants and the CTRL_* constants.

3.5 新版功能.

class signal.Handlers

enum.IntEnum collection the constants SIG_DFL and SIG_IGN.

3.5 新版功能.

class signal.Sigmasks

enum.IntEnum collection the constants SIG_BLOCK, SIG_UNBLOCK and SIG_SETMASK.

可用性: Unix。

3.5 新版功能.

在 signal 模塊中定義的變量是:

signal.SIG_DFL

這是兩種標(biāo)準(zhǔn)信號處理選項(xiàng)之一;它只會(huì)執(zhí)行信號的默認(rèn)函數(shù)。 例如,在大多數(shù)系統(tǒng)上,對于 SIGQUIT 的默認(rèn)操作是轉(zhuǎn)儲核心并退出,而對于 SIGCHLD 的默認(rèn)操作是簡單地忽略它。

signal.SIG_IGN

這是另一個(gè)標(biāo)準(zhǔn)信號處理程序,它將簡單地忽略給定的信號。

signal.SIGABRT

來自 abort(3)) 的中止信號。

signal.SIGALRM

來自 alarm(2)) 的計(jì)時(shí)器信號。

可用性: Unix。

signal.SIGBREAK

來自鍵盤的中斷 (CTRL + BREAK)。

可用性: Windows。

signal.SIGBUS

總線錯(cuò)誤 (非法的內(nèi)存訪問)。

可用性: Unix。

signal.SIGCHLD

子進(jìn)程被停止或終結(jié)。

可用性: Unix。

signal.SIGCLD

SIGCHLD 的別名。

signal.SIGCONT

如果進(jìn)程當(dāng)前已停止則繼續(xù)執(zhí)行它

可用性: Unix。

signal.SIGFPE

浮點(diǎn)異常。 例如除以零。

參見

當(dāng)除法或求余運(yùn)算的第二個(gè)參數(shù)為零時(shí)會(huì)引發(fā) ZeroDivisionError 。

signal.SIGHUP

在控制終端上檢測到掛起或控制進(jìn)程的終止。

可用性: Unix。

signal.SIGILL

非法指令。

signal.SIGINT

來自鍵盤的中斷 (CTRL + C)。

默認(rèn)的動(dòng)作是引發(fā) KeyboardInterrupt。

signal.SIGKILL

終止信號。

它不能被捕獲、阻塞或忽略。

可用性: Unix。

signal.SIGPIPE

損壞的管道:寫入到?jīng)]有讀取器的管道。

默認(rèn)的動(dòng)作是忽略此信號。

可用性: Unix。

signal.SIGSEGV

段錯(cuò)誤:無效的內(nèi)存引用。

signal.SIGSTKFLT

Stack fault on coprocessor. The Linux kernel does not raise this signal: it can only be raised in user space.

Availability: Linux.

On architectures where the signal is available. See the man page signal(7)) for further information.

3.11 新版功能.

signal.SIGTERM

終結(jié)信號。

signal.SIGUSR1

用戶自定義信號 1。

可用性: Unix。

signal.SIGUSR2

用戶自定義信號 2。

可用性: Unix。

signal.SIGWINCH

窗口調(diào)整大小信號。

可用性: Unix。

SIG*

所有信號編號都是符號化定義的。 例如,掛起信號被定義為 signal.SIGHUP;變量的名稱與 C 程序中使用的名稱相同,具體見 。 ‘signal()‘ 的 Unix 手冊頁面列出了現(xiàn)有的信號 (在某些系統(tǒng)上這是 signal(2)),在其他系統(tǒng)中此列表則是在 signal(7)) 中)。 請注意并非所有系統(tǒng)都會(huì)定義相同的信號名稱集;只有系統(tǒng)所定義的名稱才會(huì)由此模塊來定義。

signal.CTRL_C_EVENT

對應(yīng)于 Ctrl+C 擊鍵事件的信號。此信號只能用于 os.kill() 。

可用性: Windows。

3.2 新版功能.

signal.CTRL_BREAK_EVENT

對應(yīng)于 Ctrl+Break 擊鍵事件的信號。此信號只能用于 os.kill() 。

可用性: Windows。

3.2 新版功能.

signal.NSIG

One more than the number of the highest signal number. Use valid_signals() to get valid signal numbers.

signal.ITIMER_REAL

實(shí)時(shí)遞減間隔計(jì)時(shí)器,并在到期時(shí)發(fā)送 SIGALRM 。

signal.ITIMER_VIRTUAL

僅在進(jìn)程執(zhí)行時(shí)遞減間隔計(jì)時(shí)器,并在到期時(shí)發(fā)送 SIGVTALRM 。

signal.ITIMER_PROF

當(dāng)進(jìn)程執(zhí)行時(shí)以及當(dāng)系統(tǒng)替進(jìn)程執(zhí)行時(shí)都會(huì)減小間隔計(jì)時(shí)器。 這個(gè)計(jì)時(shí)器與 ITIMER_VIRTUAL 相配結(jié),通常被用于分析應(yīng)用程序在用戶和內(nèi)核空間中花費(fèi)的時(shí)間。 SIGPROF 會(huì)在超期時(shí)被發(fā)送。

signal.SIG_BLOCK

pthread_sigmask() 的 how 形參的一個(gè)可能的值,表明信號將會(huì)被阻塞。

3.3 新版功能.

signal.SIG_UNBLOCK

pthread_sigmask() 的 how 形參的是個(gè)可能的值,表明信號將被解除阻塞。

3.3 新版功能.

signal.SIG_SETMASK

pthread_sigmask() 的 how 形參的一個(gè)可能的值,表明信號掩碼將要被替換。

3.3 新版功能.

signal 模塊定義了一個(gè)異常:

exception signal.ItimerError

作為來自下層 setitimer() 或 getitimer() 實(shí)現(xiàn)錯(cuò)誤的信號被引發(fā)。 如果將無效的定時(shí)器或負(fù)的時(shí)間值傳給 setitimer() 就導(dǎo)致這個(gè)錯(cuò)誤。 此錯(cuò)誤是 OSError 的子類型。

3.3 新版功能: 此錯(cuò)誤是 IOError 的子類型,現(xiàn)在則是 OSError 的別名。

signal 模塊定義了以下函數(shù):

signal.alarm(time)

如果 time 值非零,則此函數(shù)將要求將一個(gè) SIGALRM 信號在 time 秒內(nèi)發(fā)往進(jìn)程。 任何在之前排入計(jì)劃的警報(bào)都會(huì)被取消(在任何時(shí)刻都只能有一個(gè)警報(bào)被排入計(jì)劃)。 后續(xù)的返回值將是任何之前設(shè)置的警報(bào)被傳入之前的秒數(shù)。 如果 time 值為零,則不會(huì)將任何警報(bào)排入計(jì)劃,并且任何已排入計(jì)劃的警報(bào)都會(huì)被取消。 如果返回值為零,則目前沒有任何警報(bào)被排入計(jì)劃。

可用性: Unix。

signal.getsignal(signalnum)

返回當(dāng)前用于信號 signalnum 的信號處理程序。 返回值可以是一個(gè) Python 可調(diào)用對象,或是特殊值 signal.SIG_IGN, signal.SIG_DFL 或 None 之一。 在這里,signal.SIG_IGN 表示信號在之前被忽略,signal.SIG_DFL 表示之前在使用默認(rèn)的信號處理方式,而 None 表示之前的信號處理程序未由 Python 安裝。

signal.strsignal(signalnum)

返回信號 signalnum 的系統(tǒng)描述,例如 “Interrupt”, “Segmentation fault” 等等。 如果信號無法被識別則返回 None。

3.8 新版功能.

signal.valid_signals()

返回本平臺上的有效信號編號集。 這可能會(huì)少于 range(1, NSIG),如果某些信號被系統(tǒng)保留作為內(nèi)部使用的話。

3.8 新版功能.

signal.pause()

使進(jìn)程休眠直至接收到一個(gè)信號;然后將會(huì)調(diào)用適當(dāng)?shù)奶幚沓绦颉?返回空值。

可用性: Unix。

另請參閱 sigwait(), sigwaitinfo(), sigtimedwait() 和 sigpending()。

signal.raise_signal(signum)

向調(diào)用方進(jìn)程發(fā)送一個(gè)信號。 返回空值。

3.8 新版功能.

signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)

發(fā)送信號 sig 到文件描述符 pidfd 所指向的進(jìn)程。 Python 目前不支持 siginfo 形參;它必須為 None。 提供 flags 參數(shù)是為了將來擴(kuò)展;當(dāng)前未定義旗標(biāo)值。

更多信息請參閱 pidfd_send_signal(2)) 手冊頁面。

Availability: Linux >= 5.1

3.9 新版功能.

signal.pthread_kill(thread_id, signalnum)

將信號 signalnum 發(fā)送至與調(diào)用者在同一進(jìn)程中另一線程 thread_id。 目標(biāo)線程可被用于執(zhí)行任何代碼(Python或其它)。 但是,如果目標(biāo)線程是在執(zhí)行 Python 解釋器,則 Python 信號處理程序?qū)?由主解釋器的主線程來執(zhí)行。 因此,將信號發(fā)送給特定 Python 線程的唯一作用在于強(qiáng)制讓一個(gè)正在運(yùn)行的系統(tǒng)調(diào)用失敗并拋出 InterruptedError。

使用 threading.get_ident() 或 threading.Thread 對象的 ident 屬性為 thread_id 獲取合適的值。

如果 signalnum 為 0,則不會(huì)發(fā)送信號,但仍然會(huì)執(zhí)行錯(cuò)誤檢測;這可被用來檢測目標(biāo)線程是否仍在運(yùn)行。

引發(fā)一個(gè) 審計(jì)事件 signal.pthread_kill,附帶參數(shù) thread_id, signalnum。

可用性: Unix。

另請參閱 os.kill()。

3.3 新版功能.

signal.pthread_sigmask(how, mask)

獲取和/或修改調(diào)用方線程的信號掩碼。 信號掩碼是一組傳送過程目前為調(diào)用者而阻塞的信號集。 返回舊的信號掩碼作為一組信號。

該調(diào)用的行為取決于 how 的值,具體見下。

  • SIG_BLOCK: 被阻塞信號集是當(dāng)前集與 mask 參數(shù)的并集。

  • SIG_UNBLOCK: mask 中的信號會(huì)從當(dāng)前已阻塞信號集中被移除。 允許嘗試取消對一個(gè)非阻塞信號的阻塞。

  • SIG_SETMASK: 已阻塞信號集會(huì)被設(shè)為 mask 參數(shù)的值。

mask 是一個(gè)信號編號集合 (例如 {signal.SIGINT, signal.SIGTERM})。 請使用 valid_signals() 表示包含所有信號的完全掩碼。

例如,signal.pthread_sigmask(signal.SIG_BLOCK, []) 會(huì)讀取調(diào)用方線程的信號掩碼。

SIGKILL 和 SIGSTOP 不能被阻塞。

可用性: Unix。

另請參閱 pause(), sigpending() 和 sigwait()。

3.3 新版功能.

signal.setitimer(which, seconds, interval=0.0)

設(shè)置由 which 指明的給定間隔計(jì)時(shí)器 (signal.ITIMER_REAL, signal.ITIMER_VIRTUAL 或 signal.ITIMER_PROF 之一) 在 seconds 秒 (接受浮點(diǎn)數(shù)值,為與 alarm() 之差) 之后開始并在每 interval 秒間隔時(shí) (如果 interval 不為零) 啟動(dòng)。 由 which 指明的間隔計(jì)時(shí)器可通過將 seconds 設(shè)為零來清空。

當(dāng)一個(gè)間隔計(jì)時(shí)器啟動(dòng)時(shí),會(huì)有信號發(fā)送至進(jìn)程。 所發(fā)送的具體信號取決于所使用的計(jì)時(shí)器;signal.ITIMER_REAL 將發(fā)送 SIGALRM, signal.ITIMER_VIRTUAL 將發(fā)送 SIGVTALRM, 而 signal.ITIMER_PROF 將發(fā)送 SIGPROF.

原有的值會(huì)以元組: (delay, interval) 的形式被返回。

嘗試傳入無效的計(jì)時(shí)器將導(dǎo)致 ItimerError。

可用性: Unix。

signal.getitimer(which)

返回由 which 指明的給定間隔計(jì)時(shí)器當(dāng)前的值。

可用性: Unix。

signal.set_wakeup_fd(fd, **, warn_on_full_buffer=True*)

將喚醒文件描述符設(shè)為 fd。 當(dāng)接收到信號時(shí),會(huì)將信號編號以單個(gè)字節(jié)的形式寫入 fd。 這可被其它庫用來喚醒一次 poll 或 select 調(diào)用,以允許該信號被完全地處理。

原有的喚醒 fd 會(huì)被返回(或者如果未啟用文件描述符喚醒則返回 -1)。 如果 fd 為 -1,文件描述符喚醒會(huì)被禁用。 如果不為 -1,則 fd 必須為非阻塞型。 需要由庫來負(fù)責(zé)在重新調(diào)用 poll 或 select 之前從 fd 移除任何字節(jié)數(shù)據(jù)。

當(dāng)啟用線程用時(shí),此函數(shù)只能從 主解釋器的主線程 被調(diào)用;嘗試從另一線程調(diào)用它將導(dǎo)致 ValueError 異常被引發(fā)。

使用此函數(shù)有兩種通常的方式。 在兩種方式下,當(dāng)有信號到達(dá)時(shí)你都是用 fd 來喚醒,但之后它們在確定達(dá)到的一個(gè)或多個(gè)信號 which 時(shí)存在差異。

在第一種方式下,我們從 fd 的緩沖區(qū)讀取數(shù)據(jù),這些字節(jié)值會(huì)給你信號編號。 這種方式很簡單,但在少數(shù)情況下會(huì)發(fā)生問題:通常 fd 將有緩沖區(qū)空間大小限制,如果信號到達(dá)得太多且太快,緩沖區(qū)可能會(huì)爆滿,有些信號可能丟失。 如果你使用此方式,則你應(yīng)當(dāng)設(shè)置 warn_on_full_buffer=True,當(dāng)信號丟失時(shí)這至少能將警告消息打印到 stderr。

在第二種方式下,我們 只會(huì) 將喚醒 fd 用于喚醒,而忽略實(shí)際的字節(jié)值。 在此情況下,我們所關(guān)心的只有 fd 的緩沖區(qū)為空還是不為空;爆滿的緩沖區(qū)完全不會(huì)導(dǎo)致問題。 如果你使用此方式,則你應(yīng)當(dāng)設(shè)置 warn_on_full_buffer=False,這樣你的用戶就不會(huì)被虛假的警告消息所迷惑。

在 3.5 版更改: 在 Windows 上,此函數(shù)現(xiàn)在也支持套接字處理。

在 3.7 版更改: 添加了 warn_on_full_buffer 形參。

signal.siginterrupt(signalnum, flag)

更改系統(tǒng)調(diào)用重啟行為:如果 flag 為 False,系統(tǒng)調(diào)用將在被信號 signalnum 中斷時(shí)重啟,否則系統(tǒng)調(diào)用將被中斷。 返回空值。

可用性: Unix。

請注意用 signal() 安裝信號處理程序?qū)⒅貑⑿袨橹刂脼榭赏ㄟ^顯式調(diào)用 siginterrupt() 并為給定信號的 flag 設(shè)置真值來實(shí)現(xiàn)中斷。

signal.signal(signalnum, handler)

將信號 signalnum 的處理程序設(shè)為函數(shù) handler。 handler 可以為接受兩個(gè)參數(shù)(見下)的 Python 可調(diào)用對象,或者為特殊值 signal.SIG_IGN 或 signal.SIG_DFL 之一。 之前的信號處理程序?qū)⒈环祷兀▍⒁娚衔?getsignal() 的描述)。 (更多信息請參閱 Unix 手冊頁面 signal(2))。)

當(dāng)啟用線程用時(shí),此函數(shù)只能從 主解釋器的主線程 被調(diào)用;嘗試從另一線程調(diào)用它將導(dǎo)致 ValueError 異常被引發(fā)。

handler 將附帶兩個(gè)參數(shù)調(diào)用:信號編號和當(dāng)前堆棧幀 (None 或一個(gè)幀對象;有關(guān)幀對象的描述請參閱 類型層級結(jié)構(gòu)描述 或者參閱 inspect 模塊中的屬性描述)。

在 Windows 上,signal() 調(diào)用只能附帶 SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM 或 SIGBREAK。 任何其他值都將引發(fā) ValueError。 請注意不是所有系統(tǒng)都定義了同樣的信號名稱集合;如果一個(gè)信號名稱未被定義為 SIG* 模塊層級常量則將引發(fā) AttributeError。

signal.sigpending()

檢查正在等待傳送給調(diào)用方線程的信號集合(即在阻塞期間被引發(fā)的信號)。 返回正在等待的信號集合。

可用性: Unix。

另請參閱 pause(), pthread_sigmask() 和 sigwait()。

3.3 新版功能.

signal.sigwait(sigset)

掛起調(diào)用方線程的執(zhí)行直到信號集合 sigset 中指定的信號之一被傳送。 此函數(shù)會(huì)接受該信號(將其從等待信號列表中移除),并返回信號編號。

可用性: Unix。

另請參閱 pause(), pthread_sigmask(), sigpending(), sigwaitinfo() 和 sigtimedwait()。

3.3 新版功能.

signal.sigwaitinfo(sigset)

掛起調(diào)用方線程的執(zhí)行直到信號集合 sigset 中指定的信號之一被傳送。 此函數(shù)會(huì)接受該信號并將其從等待信號列表中移除。 如果 sigset 中的信號之一已經(jīng)在等待調(diào)用方線程,此函數(shù)將立即返回并附帶有關(guān)該信號的信息。 被傳送信號的信號處理程序不會(huì)被調(diào)用。 如果該函數(shù)被某個(gè)不在 sigset 中的信號中斷則會(huì)引發(fā) InterruptedError。

返回值是一個(gè)代表 siginfo_t 結(jié)構(gòu)體所包含數(shù)據(jù)的對象,具體為: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band。

可用性: Unix。

另請參閱 pause(), sigwait() 和 sigtimedwait()。

3.3 新版功能.

在 3.5 版更改: 當(dāng)被某個(gè) 不在 sigset 中的信號中斷時(shí)本函數(shù)將進(jìn)行重試并且信號處理程序不會(huì)引發(fā)異常(請參閱 PEP 475 了解其理由)。

signal.sigtimedwait(sigset, timeout)

類似于 sigwaitinfo(),但會(huì)接受一個(gè)額外的 timeout 參數(shù)來指定超時(shí)限制。 如果將 timeout 指定為 0,則會(huì)執(zhí)行輪詢。 如果發(fā)生超時(shí)則返回 None。

可用性: Unix。

另請參閱 pause(), sigwait() 和 sigwaitinfo()。

3.3 新版功能.

在 3.5 版更改: 現(xiàn)在當(dāng)此函數(shù)被某個(gè)不在 sigset 中的信號中斷時(shí)將以計(jì)算出的 timeout 進(jìn)行重試并且信號處理程序不會(huì)引發(fā)異常(請參閱 PEP 475 了解其理由)。

Examples

這是一個(gè)最小示例程序。 它使用 alarm() 函數(shù)來限制等待打開一個(gè)文件所花費(fèi)的時(shí)間;這在文件為無法開啟的串行設(shè)備時(shí)會(huì)很有用處,此情況通常會(huì)導(dǎo)致 os.open() 無限期地掛起。 解決辦法是在打開文件之前設(shè)置 5 秒鐘的 alarm;如果操作耗時(shí)過長,將會(huì)發(fā)送 alarm 信號,并且處理程序會(huì)引發(fā)一個(gè)異常。

 
 
 
 
  1. import signal, os
  2. def handler(signum, frame):
  3. signame = signal.Signals(signum).name
  4. print(f'Signal handler called with signal {signame} ({signum})')
  5. raise OSError("Couldn't open device!")
  6. # Set the signal handler and a 5-second alarm
  7. signal.signal(signal.SIGALRM, handler)
  8. signal.alarm(5)
  9. # This open() may hang indefinitely
  10. fd = os.open('/dev/ttyS0', os.O_RDWR)
  11. signal.alarm(0) # Disable the alarm

對于 SIGPIPE 的說明

將你的程序用管道輸出到工具例如 head(1)) 將會(huì)導(dǎo)致 SIGPIPE 信號在其標(biāo)準(zhǔn)輸出的接收方提前關(guān)閉時(shí)被發(fā)送到你的進(jìn)程。 這將引發(fā)一個(gè)異常例如 BrokenPipeError: [Errno 32] Broken pipe。 要處理這種情況,請對你的入口點(diǎn)進(jìn)行包裝以捕獲此異常,如下所示:

 
 
 
 
  1. import os
  2. import sys
  3. def main():
  4. try:
  5. # simulate large output (your code replaces this loop)
  6. for x in range(10000):
  7. print("y")
  8. # flush output here to force SIGPIPE to be triggered
  9. # while inside this try block.
  10. sys.stdout.flush()
  11. except BrokenPipeError:
  12. # Python flushes standard streams on exit; redirect remaining output
  13. # to devnull to avoid another BrokenPipeError at shutdown
  14. devnull = os.open(os.devnull, os.O_WRONLY)
  15. os.dup2(devnull, sys.stdout.fileno())
  16. sys.exit(1) # Python exits with error code 1 on EPIPE
  17. if __name__ == '__main__':
  18. main()

請不要將 SIGPIPE 的處置方式設(shè)為 SIG_DFL 以避免 BrokenPipeError。 這樣做還會(huì)在你的程序所寫入的任何套接字連接中斷時(shí)導(dǎo)致你的程序異常退出。

有關(guān)信號處理句柄和異常的注釋

如果一個(gè)信號處理句柄引發(fā)了異常,該異常將被傳播到主線程并可能在任何 bytecode 指令之后被引發(fā),在執(zhí)行期間的任何時(shí)候都可能出現(xiàn) KeyboardInterrupt。 大多數(shù) Python 代碼,包括標(biāo)準(zhǔn)庫的代碼都不能對此進(jìn)行健壯性處理,因此 KeyboardInterrupt (或由信號處理句柄所導(dǎo)致的任何其他異常) 可能會(huì)在極少數(shù)情況下使程序處于非預(yù)期的狀態(tài)。

為了展示這個(gè)問題,請考慮以下代碼:

 
 
 
 
  1. class SpamContext:
  2. def __init__(self):
  3. self.lock = threading.Lock()
  4. def __enter__(self):
  5. # If KeyboardInterrupt occurs here, everything is fine
  6. self.lock.acquire()
  7. # If KeyboardInterrupt occurs here, __exit__ will not be called
  8. ...
  9. # KeyboardInterrupt could occur just before the function returns
  10. def __exit__(self, exc_type, exc_val, exc_tb):
  11. ...
  12. self.lock.release()

對于許多程序,特別是那些在遇到 KeyboardInterrupt 只需直接退出的程序來說,這不是個(gè)問題,但是高復(fù)雜度或要求高可靠性的應(yīng)用程序則應(yīng)當(dāng)避免由于信號處理句柄引發(fā)異常。 他們還應(yīng)當(dāng)避免將捕獲 KeyboardInterrupt 作為程序關(guān)閉的優(yōu)雅方式。 相反地,他們應(yīng)當(dāng)安裝自己的 SIGINT 處理句柄。 下面是一個(gè)避免了 KeyboardInterrupt 的 HTTP 服務(wù)器示例:

 
 
 
 
  1. import signal
  2. import socket
  3. from selectors import DefaultSelector, EVENT_READ
  4. from http.server import HTTPServer, SimpleHTTPRequestHandler
  5. interrupt_read, interrupt_write = socket.socketpair()
  6. def handler(signum, frame):
  7. print('Signal handler called with signal', signum)
  8. interrupt_write.send(b'\0')
  9. signal.signal(signal.SIGINT, handler)
  10. def serve_forever(httpd):
  11. sel = DefaultSelector()
  12. sel.register(interrupt_read, EVENT_READ)
  13. sel.register(httpd, EVENT_READ)
  14. while True:
  15. for key, _ in sel.select():
  16. if key.fileobj == interrupt_read:
  17. interrupt_read.recv(1)
  18. return
  19. if key.fileobj == httpd:
  20. httpd.handle_request()
  21. print("Serving on port 8000")
  22. httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
  23. serve_forever(httpd)
  24. print("Shutdown...")

文章標(biāo)題:創(chuàng)新互聯(lián)Python教程:signal—-設(shè)置異步事件處理程序
當(dāng)前鏈接:http://www.dlmjj.cn/article/dpeeecc.html