ホームページ  >  記事  >  バックエンド開発  >  Python はシグナル モジュールを使用してスケジュールされた実行を実装します

Python はシグナル モジュールを使用してスケジュールされた実行を実装します

高洛峰
高洛峰オリジナル
2016-10-17 16:51:401436ブラウズ

liunx システムでは、1 分ごとにコマンドを実行したい場合、最も一般的な方法は crontab です。crontab を使用したくない場合は、タイマーを使用してこの機能を実現できると同僚が指摘しました。プログラムを探索し始めて、シグナルについての知識が必要であることがわかりました...

Linux がサポートしているシグナルを確認してください: kill -l

root@server:~# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
root@server:~#

シグナル: プロセス間の通信方法であり、ソフトウェア割り込みです。プロセスがシグナルを受信すると、元のプログラムの実行フローを中断してシグナルを処理します。オペレーティング システムは、シグナル受信後のプロセスのデフォルトの動作を規定していますが、シグナル処理関数をバインドすることで、シグナル受信後のプロセスの動作を変更できます。SIGTOP と SIGKILL という 2 つのシグナルがあります。

シグナルを送信する理由は通常 2 つあります。

1 (パッシブ) たとえば、子プロセスが終了すると、カーネルは親プロセスに SIGCHLD シグナルを送信します。キーボードは SIGINT シグナルを送信します

2 (アクティブ (フォーム) システムコール kill を通じて指定されたプロセスにシグナルを送信します

C 言語には setitimer 関数があります。関数 setitimer はそれぞれ独立した 3 つのタイマーを提供できますその他 任意の時間が完了すると、タイミング信号がプロセスに送信され、自動的に時間がリセットされます。タイマーのタイプを決定するパラメータ:

ITIMER_REAL アラームのタイプと同じタイミングのリアルタイム。 SIGALRM

ITIMER_VIRT ユーザーモードでのスケジュールされたプロセスの実際の実行時間。 SIGVTALRM

ITIMER_PROF ユーザー モードおよびコア モードでのスケジュールされたプロセスの実際の実行時間。 SIGPROF

3 種類のタイマーは、計時完了時にプロセスに異なる信号を送信します。そのうち、ITIMER_REAL クラスのタイマーは SIGALRM 信号を送信し、ITIMER_VIRT クラスのタイマーは SIGVTALRM 信号を送信し、ITIMER_REAL クラスのタイマーは SIGPROF 信号を送信します。 。

アラーム関数は基本的に、低精度で過負荷になっていない ITIMER_REAL タイマーを設定します。精度は秒単位までであり、タイミングは設定ごとに 1 回しか生成できません。関数 setitimer によって設定されるタイマーは異なります。これらは (理論上) マイクロ秒単位で時間を計るだけでなく、時間を自動的に循環させることもできます。 Unix プロセスでは、アラーム タイマーと ITIMER_REAL タイマーを同時に使用することはできません。

SIGINT プロセスの終了 プロセスの中断 (control+c)

SIGTERM プロセスの終了 ソフトウェア終了信号

SIGKILL プロセスの終了 プロセスの強制終了

SIGALRM 目覚まし時計信号

初期の知識はほぼ準備ができたので、Python の signal に進む時が来ました。

信号名の定義

信号パッケージは、各信号名とそれに対応する整数を定義します。たとえば、

import signal
print signal.SIGALRM
print signal.SIGCONT

Python で使用される信号名は Linux と一致します。

$man 7 signal

を介して

プリセット信号処理関数をクエリできます。信号パッケージの中核は、以下に示すように、signal.signal()関数を使用して信号処理関数をプリセット(登録)することです:

singnal.signal(signalnum, handler)

signalnumはシグナル、handlerはシグナルの処理関数です。 「シグナルの基本」で、プロセスがシグナルを無視したり、デフォルトのアクションを実行したり、アクションをカスタマイズしたりできることについて説明しました。ハンドラーが signal.SIG_IGN の場合、シグナルは無視されます。ハンドラーが singal.SIG_DFL の場合、プロセスはデフォルトのアクション (デフォルト) を実行します。 handler が関数名の場合、プロセスは関数で定義されたアクションを実行します。

import signal
# Define signal handler function
def myHandler(signum, frame):
  print('I received: ', signum)
  
# register signal.SIGTSTP's handler 
signal.signal(signal.SIGTSTP, myHandler)
signal.pause()
print('End of Signal Demo')

メインプログラムでは、まず signal.signal() 関数を使用して信号処理関数をプリセットします。次に、signal.pause() を実行して、シグナルを待っているプロセスを一時停止してシグナルを待ちます。シグナル SIGUSR1 がプロセスに渡されると、プロセスは一時停止から再開し、デフォルトに従って SIGTSTP シグナル処理関数 myHandler() を実行します。 myHandler の 2 つのパラメータのうち 1 つはシグナル (signum) を識別するために使用され、もう 1 つはシグナル発生時のプロセス スタックのステータス (スタック フレーム) を取得するために使用されます。どちらのパラメータも signal.singnal() 関数によって渡されます。

上記のプログラムはファイル(test.pyなど)に保存できます。次のメソッドを使用して実行します:

$python test.py

を使用してプロセスを実行します。プログラムが signal.pause() に到達すると、プロセスは一時停止し、シグナルを待ちます。この時点で、CTRL+Z を押して SIGTSTP シグナルをプロセスに送信します。プロセスが myHandle() 関数を実行し、メイン プログラムに戻って実行を継続していることがわかります。 (もちろん、$ps を使用してプロセス ID をクエリし、$kill を使用してシグナルを送信することもできます。)

(プロセスは、シグナルを待つために一時停止するために signal.pause() を使用する必要はありません。動作中にシグナルを受信することもできます。たとえば、上記の signal.pause() を動作に時間がかかるループに変更します)

独自のニーズに応じて myHandler() の操作を変更できます。さまざまな信号に対するパーソナライズされた処理。

定期的に SIGALRM シグナルを送信します

便利な関数は signal.alarm() です。これは、一定期間後に SIGALRM シグナルをプロセス自体に送信するために使用されます:

import signal
# Define signal handler function
def myHandler(signum, frame):
  print("Now, it's the time")
  exit()
  
# register signal.SIGALRM's handler 
signal.signal(signal.SIGALRM, myHandler)
signal.alarm(5)
while True:
  print('not yet')

ここでは無限ループを使用しますプロセスを実行し続けるようにします。 signal.alarm() が 5 秒間実行された後、プロセスは SIGALRM シグナルをそれ自体に送信し、信号処理関数 myHandler の実行を開始します。

发送信号

signal包的核心是设置信号处理函数。除了signal.alarm()向自身发送信号之外,并没有其他发送信号的功能。但在os包中,有类似于linux的kill命令的函数,分别为

os.kill(pid, sid)
os.killpg(pgid, sid)

分别向进程和进程组(见Linux进程关系)发送信号。sid为信号所对应的整数或者singal.SIG*。

实际上signal, pause,kill和alarm都是Linux应用编程中常见的C库函数,在这里,我们只不过是用Python语言来实现了一下。实际上,Python 的解释器是使用C语言来编写的,所以有此相似性也并不意外。此外,在Python 3.4中,signal包被增强,信号阻塞等功能被加入到该包中。我们暂时不深入到该包中。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。