DOBON.NETプログラミング道掲示板
(現在 過去ログ1 を表示中)

[ 最新記事及び返信フォームをトピックトップへ ]

■33356 / inTopicNo.1)  定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
  
□投稿者/ ともぞう 一般人(1回)-(2016/04/30(Sat) 23:11:57)
  • アイコン環境/言語:[C#] 
    分類:[.NET] 

    はじめまして。ともぞうと申します。

    【背景】
    現在、メインスレッドとは別スレッドで定期的にバックグラウンド処理を行うプログラムを作成しております。

    バックグラウンド処理の実行間隔は1分程度(多少の誤差はOK)であり、下記のバックグラウンド処理を行います。
    ・DBからのデータ取得や更新処理
    ・UIの更新処理は行わない

    定期的に実行する仕組みとしては、下記の4つの技術が考えられるかと思います。

    ・System.Windows.Forms.Timer
    ・System.Threading.Timer
    ・System.Timers.Timer
    ・SleepとWhile文を使用した方法(無限ループの中でSleep。下記、Sleepと記載します。)

    【ご質問】
    定期的にバックグラウンド処理を呼び出す仕組みについて、何が最適なのかを検討しておりますが、「そもそも、どういった時にSleep使うのか?」など、Sleepを使うケースを調べてみたのですが、有効な情報が見つからず、決めかねている状況です。

    そのため、下記の2点について、ご教授頂けないでしょうか?

    1.Timerではなく、Sleepを採用するケースはどんな時なのか?
    2.Sleepを採用してはいけないケースはどんな時なのか?


    ・実現したい事から考えると、最適な技術は「System.Threading.Timer(or System.Timers.Timer)」か「Sleep」ではないかと考えています。

    ・Stack Overflowなどでも「Timer VS Sleep」などの記事も見つかり、読んでは見たのですが、英語であり、良くわからず・・・という状況です。

    ・Sleep処理は下記の内容を確認しております。
    http://blogs.wankuma.com/jitta/archive/2010/05/08/188819.aspx

引用返信 削除キー/
■33357 / inTopicNo.2)  Re[1]: 定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
□投稿者/ Azulean 大御所(465回)-(2016/05/01(Sun) 00:14:03)
  • アイコンNo33356に返信(ともぞうさんの記事)
    > 1.Timerではなく、Sleepを採用するケースはどんな時なのか?

    今回のケースでは Sleep を挙げるのであれば、AutoResetEvent/ManualResetEvent の方が向いていると思います。
    Sleep は時間経過以外の方法で脱出する方法がないため、キャンセルが必要なケース、時間経過以外にも処理再開トリガーがあるケースでは使えません。

    Sleep を使うとしたら、本当に短時間、キャンセルなどの外部トリガーがない状態に絞って手軽に待ちを実装したい時だけだと言い切っても、言い過ぎではないと考えています。


    > 2.Sleepを採用してはいけないケースはどんな時なのか?

    私は、基本的に Sleep を使うべきではないという考えです。
    アプリの終了処理も考えれば、「時間経過以外のトリガーはない」という前提が成り立たないためです。

    イベント系(AutoResetEvent/ManualResetEvent)とタイマー系を比較するとしたら、ダメというケースはあまりない気がします。
    リスクを挙げるとしたらそれぞれ以下のようなことは言えるかと思います。

    ■イベント系
    ・ロジックミスによるデッドロックのリスク
    ・同期オブジェクトの「イベント」を知らない人は知らない(event キーワードと誤認される)

    ■タイマー系
    ・同時に処理が動いてしまうリスク
    ・選ぶタイマーによって性質がだいぶ違う


    個人的な印象ですが、比較的長時間(10 秒とか)待つのであれば、タイマー系の方が良いと思います。
引用返信 削除キー/
■33359 / inTopicNo.3)  Re[2]: 定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
□投稿者/ ともぞう 一般人(2回)-(2016/05/01(Sun) 17:11:16)
  • アイコンAzulean様

    ご連絡が遅くなり、申し訳ございません。
    ご教授ありがとうございます!

    >>1.Timerではなく、Sleepを採用するケースはどんな時なのか?
    >
    > 今回のケースでは Sleep を挙げるのであれば、AutoResetEvent/ManualResetEvent の方が向いていると思います。
    > Sleep は時間経過以外の方法で脱出する方法がないため、キャンセルが必要なケース、時間経過以外にも処理再開トリガーがあるケースでは使えません。
    >
    > Sleep を使うとしたら、本当に短時間、キャンセルなどの外部トリガーがない状態に絞って手軽に待ちを実装したい時だけだと言い切っても、言い過ぎではないと考えています。

    なるほど。確かにおっしゃる通りで、時間経過以外の方法では脱出する方法がないですね。
    さらに、Sleepを使ったとしても、短い時間じゃないと、途中で終了させるようなケースが出てきたらその時間だけ待つ必要が出てきてしまいますね。


    >>2.Sleepを採用してはいけないケースはどんな時なのか?
    >
    > 私は、基本的に Sleep を使うべきではないという考えです。
    > アプリの終了処理も考えれば、「時間経過以外のトリガーはない」という前提が成り立たないためです。
    >
    アプリの終了処理については、盲点でした。
    タイマー系であれば、タイマーを停止して、Disposeをすれば良いですが、Sleepの場合は、Sleepから戻るを待って、そのスレッドを破棄!?するような処理をしなければですね。
    (Sleepを使用した場合の終了のイメージが正しいかどうかは疑問ですが・・・)


    > イベント系(AutoResetEvent/ManualResetEvent)とタイマー系を比較するとしたら、ダメというケースはあまりない気がします。
    > リスクを挙げるとしたらそれぞれ以下のようなことは言えるかと思います。
    >
    > ■イベント系
    > ・ロジックミスによるデッドロックのリスク
    > ・同期オブジェクトの「イベント」を知らない人は知らない(event キーワードと誤認される)
    >
    > ■タイマー系
    > ・同時に処理が動いてしまうリスク
    > ・選ぶタイマーによって性質がだいぶ違う
    >
    >
    > 個人的な印象ですが、比較的長時間(10 秒とか)待つのであれば、タイマー系の方が良いと思います。

    AutoResetEvent/ManualResetEventは名前は聞いたことはありますが、具体的な使用方法までは把握していませんでした。
    ですので、サンプルコードもたくさん落ちているので、色々動かして確認してみます。
    ありがとうございます!

引用返信 削除キー/
■33361 / inTopicNo.4)  Re[1]: 定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
□投稿者/ 浅葱 一般人(1回)-(2016/05/02(Mon) 14:03:46)
  • アイコンNo33356に返信(ともぞうさんの記事)
    > 1.Timerではなく、Sleepを採用するケースはどんな時なのか?

    処理時間が未確定な処理をバックグラウンドで定期的に行う際に使用することがあります。

    タイマーの場合、前の処理が終わってなくても次の処理が開始されてしまう可能性があるためです。
    もちろん、処理開始時にタイマーを一旦止めて、処理終了後にタイマーを再開する方法もありますが。


    > 2.Sleepを採用してはいけないケースはどんな時なのか?

    こちらに関しては終了処理を正しく行えばいけないとこはないと思っています。
    ※使い勝手の面でタイマーを使用したほうがいい場合も有ります

    終了処理は該当スレッドへフラグを渡しAbortを実行する事で、
    WhileからのExit条件を満たすようにし、Sleep中の場合、即時ThreadAbortExceptionが発生するので待機時間はなくなります。

    再開する場合は該当スレッド開始時の処理を再度呼ぶ形で対応もできます。

    アプリの終了まで動かう場合は該当スレッドのIsBackgroundプロパティをtrueに設定しておけばメインスレッドの終了時に該当スレッドは強制的に終了しますので終了漏れもなくなります。


    ※「Sleepが優位!」「Sleepを使うべき!」といっているつもりはありません。
    こんな場合に使ってるよという程度で受け取って、ご自身の状況に応じた方法で実装下さい。

引用返信 削除キー/
■33363 / inTopicNo.5)  Re[2]: 定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
□投稿者/ Azulean 大御所(466回)-(2016/05/03(Tue) 18:02:17)
  • アイコンThread.Abort の話題が出たので念のため。

    一般論として、Thread.Abort は「使ってはならない」といった位置づけにあります。
    MSDN でも述べられていますが、Abort を呼ぶと即座にスレッドが終了してしまうため、Dispose 処理、リソース解放処理などが呼ばれないなどの不都合が生じる恐れがあるためです。
    https://msdn.microsoft.com/ja-jp/library/ty8d3wta(v=vs.100).aspx


    「終了時に限る」のであれば、プロセス終了によって強制的に解放されるリソースの方が大半ではありますが、たとえば一時ファイル、一時ディレクトリといったものを作っている場合はそれらが残るかもしれません。
    ご自身が作っているプログラム、使用しているライブラリの性質をきちんと理解し、リスクも考慮して使う分にはご自身の責任で…。

    // 「使うな」という主張をするつもりはありません。
    // Thread.Abort の性質を念のため書き添えた次第です。
引用返信 削除キー/
■33364 / inTopicNo.6)  Re[3]: 定期的なバックグランド処理で「SleepとWhile文を使用した方法」を使うケースについて
□投稿者/ ともぞう 一般人(3回)-(2016/05/05(Thu) 18:21:21)
  • アイコン浅葱様、Azulean様

    ありがとうございます!

    Sleepを使用した際には、終了処理をどのようにするのが最適なのかを考えていました。

    >■No33361に返信(浅葱さんの記事)
    >終了処理は該当スレッドへフラグを渡しAbortを実行する事で、
    >WhileからのExit条件を満たすようにし、Sleep中の場合、即時ThreadAbortExceptionが発生するので待機時間はなくなります。

    >再開する場合は該当スレッド開始時の処理を再度呼ぶ形で対応もできます。

    >アプリの終了まで動かう場合は該当スレッドのIsBackgroundプロパティをtrueに設定しておけばメインスレッドの終了時に該当スレッドは強制的に終了しますので終了漏れもなくなります。

    Sleep中にAbortをすると、例外が発生するとは知りませんでした。試してみます。
    また、IsBackgroundプロパティをtrueにすると、メインスレッドが終了すれば強制的に終了するということも知りませんでした。

    >■No33363に返信(Azuleanさんの記事)
    > 一般論として、Thread.Abort は「使ってはならない」といった位置づけにあります。
    > MSDN でも述べられていますが、Abort を呼ぶと即座にスレッドが終了してしまうため、Dispose 処理、リソース解放処理などが呼ばれないなどの不都合が生じる恐れがあるためです。
    > https://msdn.microsoft.com/ja-jp/library/ty8d3wta(v=vs.100).aspx
    >
    >
    > 「終了時に限る」のであれば、プロセス終了によって強制的に解放されるリソースの方が大半ではありますが、たとえば一時ファイル、一時ディレクトリといったものを作っている場合はそれらが残るかもしれません。
    > ご自身が作っているプログラム、使用しているライブラリの性質をきちんと理解し、リスクも考慮して使う分にはご自身の責任で…。
    >
    ありがとうございます!

    おっしゃる通り、Abortは処理が途中の状態になる可能性があるので、アプリを終了しても、プロセスが使用中のまま残ってしまう、というリスクがあるなと考えていました。
    要件次第というところはありますが、使うのであれば、そういったリスクも考慮して使用します。


    本件に関して、Azulean様、浅葱様に有益な情報を頂きましたので、解決としたいと思います!

    ありがとうございました!


解決み!
引用返信 削除キー/



トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

Mode/  Pass/


- Child Tree -