準・究極の選択

scanfやデーモンのような、while無限ループによるものではない、待ち状態は処理をせず、トリガーがきたら処理を行うプログラムをPythonで書くには、どうすれば良いでしょうか?

キューを受け取って溜まっているときは処理を行うし、溜まっていなければ処理をしないようなプログラムは可能でしょうか?

sleepを入れたwhile無限ループしかないのでしょうか

質問者からの補足コメント

  • うれしい

    ラズパイのRaspbianです!

      補足日時:2020/02/23 21:09
  • HAPPY

    専門知識ありがとうございます!

    v4l2さんに質問なんですが、
    「データがキューにたまれば、受信データ処理ルーチンが呼び出されるような割り込み処理(トリガー処理)」
    について、
    そもそも、そのデータがキューに溜まったことを検知して割り込み処理させるために、
    while無限ループが必要なのではないでしょうか?

    c言語やアセンブリならば、
    データがキューに溜まったことを検知できるのでしょうか?

      補足日時:2020/02/23 22:02
  • うれしい

    返答ありがとうございます!

    selectモジュールについて、ちょっと調べたところ、
    ポーリングをして一定時間間隔で調べに行っているらしいのですが、
    これはwhile無限ループとは違うのでしょうか
    そもそもわたしの解釈が間違いでしょうか?

    scanf、input、のようなcpu負荷をかけないような待ち方をしたいのですが、
    複数プロセスからのキューを待ち受けるような
    イベント駆動のプログラムを書きたい時には
    GUIの何かしらの機能を使う、ソケット通信のlistenで待つなど、をしなければならないのでしょうか

      補足日時:2020/02/25 01:23
  • OK

    返信ありがとうございます!

    multiprocessingの Queueの
    get()はちゃんとブロックするようになっているんですね。
    今までempty()でいちいちチェックしていました。
    ありがとうございます!
    試したところcpu負荷も低いままになりました!


    selectを初めて知りました!
    使い方は書いてくださったコードでだいたい分かりました。
    マシンに関するあらゆる入力などを待てるのですね。
    また、cpuを使わずに、osからのイベントを待てるのですね!ありがとうございます!
    限界の、一定時間待つ、というタイムアウト時間だったのですね!


    ウェブソケットは、cpu負荷をかけずにosからのイベント、システムコールを待っていてくれてると分かりました!
    それがいろんな種類の時、
    スレッドやプロセスでそれぞれ待つ、や、selectを使えば良いのですね。

    ありがとうございます!

      補足日時:2020/02/26 21:40

A 回答 (9件)

>キューを受け取って溜まっているときは処理を行うし、


>溜まっていなければ処理をしないようなプログラムは可能でしょうか?

同期キューの Queu モジュールで出来ますよ。
Queuのgetメソッドはキューが空なら処理をブロック出来ます。
    • good
    • 0

大元の質問は下記でよいでしょうか。


https://oshiete.goo.ne.jp/qa/11497059.html
こちらの方にも回答しましたが、Websocketを使うということなら受信待ちはwebsocketパッケージの中でやってくれるので自前で無限ループを書く必要はなく、各種イベントハンドラを登録してイベントループを行う関数(run_forever)を呼び出すだけです。イベントが発生したら該当のイベントハンドラが呼び出されるのでイベントハンドラに処理を記述します。
イベントループの止め方はパッケージのマニュアルを確認ください。基本的にはイベントハンドラの中で何か関数を呼び出すか、イベントハンドラの返値でループを止めさせます。

自前でイベントループを書くという話になると、while無限ループは基本です。ただしループを全力で廻すとCPUを浪費するので、イベント発生を待つ処理(システムコール)を呼び出してイベント発生まで待つようにします。
イベントループの基本的なフローは以下のようになります。

while True:
 イベント発生待ち(listen, recv, selectなど)
 イベント識別と処理
 if 終了判定:
  break
終了処理

重要なのはイベントループで待てるのが一か所だということです。
例えばTCP/IPサーバでソケット接続待ちとデータ受信待ちをそれぞれ別の待ちにしてしまうと、接続待ちのときにはデータを受信できず、受信待ちしていると新しい接続がきても繋げません。
これを解決する一つの方法がselectです。selectは複数のイベント待ちを同時に管理し、いずれかのイベントが発生すると返ってきます。返値から発生したイベントを識別して処理します。
他の解決策としてはマルチスレッドにして各スレッドでは一つのイベントだけ待てばよいようにするという方法もあります。
    • good
    • 0

> selectモジュールについて、ちょっと調べたところ、ポーリングをして一定時間間隔で調べに行っているらしいのですが、


違います。
OSからのイベント通知を待っているだけですので、待っている間はCPUを使いません。
キーボード入力待ちと同じです。

> ソケット通信のlistenで待つなど
listenだと、1つのソケットしか監視できませんが、selectだと複数のソケットやキーボード、パイプなどからの入力を待てます。

selectが待つのは入力だけではないですが、説明を簡単にするために、入力を待つ話だけ書きます。
ケース1.selectをコールした時点で、引数で指定した入力(広義のファイル(ファイル、ソケット、端末、パイプ等))にデータがたまっていれば、どの入力にデータがたまっているの(複数かも)か、返します。
ケース2.コールした時点でたまっていなければ、どこかの入力が来るまで待って、どこに入力があったかを返します。
ケース3.指定時間待ってもどこからも入力が無ければ、タイムアウトしたら空(何も入力が無かった)を返します。どこかの入力があるまで無限に待つこともできます。

例えば、相手とつながったTCPセッションと、端末の両方を待って、端末から入力があればTCPで相手に送り、TCPから入力があれば端末に表示するとかで使えます。

r, w, x = select.select([sys.stdin, socket],[],[])
for inp in r:
if inp == sys.stdin:
端末入力があった場合の処理(ソケットに書くとか)
if inp == socket:
TCPソケットから入力があった場合の処理(sys.stdoutに書くとか)
    • good
    • 0

マルチプロセスでプロセス間同期するならこのモジュールかな。



https://docs.python.org/ja/3/library/multiproces …
    • good
    • 0

scanfは入力待ちなので、Pythonなら input()でいいですよね?



デーモンは、普通はマルチプロセスかマルチスレッドで、
1スレッドが入力を待ち続けるか、あるいは、時々データが来ているかチェックするかですね。

https://docs.python.org/ja/3/library/select.html
を使うと、
「指定した複数の入力ストリームの1つ以上に入力データがあるか、あるいは、指定時間経つまで待つ」
という処理ができます。
    • good
    • 0

>>そもそも、そのデータがキューに溜まったことを検知して割り込み処理させるために、


while無限ループが必要なのではないでしょうか?

受信処理ではありませんが、C#のタイマー処理のサンプルとして以下のようなコードがあります。
以下のコードでは、200ms毎にtimer1_Tickが呼び出されて処理が実行されます。
でも、そのtimer1_Tickを呼び出す処理はユーザが記述する必要はありません。
こういうのは、コールバック関数といわれていて、規定の時間が来ると、InitializeComponentでtimer1_Tickが登録してあるので、勝手に呼び出されるのですね。
つまりは、whileループが無くても、割込処理でtimer1_Tickが処理されます。

そのタイマー割り込みのような感じで受信データが来たら、例えば「DataReady」って名前の関数を登録しておけばいいわけです。

ま、縁の下の力持ちルーチンとして、EventHandlerが活躍してくれているのでしょうけどね。

// デザイナーのコード
private void InitializeComponent()
{
this.timer1 = new System.Windows.Forms.Timer();
this.timer1.Enabled = true;
this.timer1.Interval = 200;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
}
private System.Windows.Forms.Timer timer1;

// ユーザーコード
private void timer1_Tick(object sender, EventArgs e)
{
// タイマーでやらせたいことを以下に記述:
//
}

なお、余談ですが、C#では、不定期に来るネットからの受信データなどの処理をGUIに影響でないように処理するために、スレッドをうまく活用して非同期処理ができる構文が用意されていたりします。

>>c言語やアセンブリならば、
データがキューに溜まったことを検知できるのでしょうか?

まあ、検知できるのでしょうか?というよりも、検知できるようなプログラムを自分で書くか、あるいは、だれかにライブラリーとして用意してもらうってことだと思います。
昔のことですが、自分ではそういったコードが書けないため、知人のベテラン・プログラマさんがアセンブラで送受信用のドライバーコードを書いてくださいました。
送受信用のLSIのレジスタをビットレベルで制御されていました。
    • good
    • 0

まずは、OS側でそういう機能が提供されているか?が問われる気がします。


提供されていれば、Python側で、その機能を利用できるようなライブラリ等を使うとか、無ければ、ライブラリを自分で作るってことになると思います。

たとえば、データ受信処理で、受信データがキューにたまり、それをPythonで処理したいとします。
whileループなら、sleepを入れて定期的にキューにデータがたまっているか?をチェックする処理になりますよね?
でも、そういうのではなく、キューにデータが入ったら、受信データ処理ルーチンが呼ばれるようにしたいとなれば、データがキューにたまれば、受信データ処理ルーチンが呼び出されるような割り込み処理(トリガー処理)になると思います。

C言語やアセンブラであれば、処理ルーチンのエントリアドレスなどを渡すことで、そういう割り込み処理が可能となった気がしますけど、Pythonは知らないので、どう書くのか残念ながらわかりません・・・。
    • good
    • 0

まずトリガーを待って、トリガーを受け取るごとに処理をして、次のトリガーを待つという無限ループ処理を自作するならwhile無限ループはほぼ必須ですね。

forで誤魔化すこともできなくはないけど本質的ではない。
あとはトリガーをどう待ってどう受け取るかです。socketでTCP/IPセッションの接続をlistenで待つとか、データ受信をrecvで待つとかだったらsleepは必要ないですね。
なお、GUIをtkinterとかで書くのだとイベントハンドラを定義してメインループを呼び出すと無限ループとかイベント待ちは中でやってくれるので自分で書く必要はないです。ボタンを押すなどのイベントが発生したら対応するイベントハンドラが呼ばれます。
    • good
    • 0

処理系は?

    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!