質問

ビジーメソッド+ C#のタイムアウトを設定する方法。

役に立ちましたか?

解決

わかりました、ここに本当の答えがあります。

...

void LongRunningMethod(object monitorSync)
{
   //do stuff    
   lock (monitorSync) {
     Monitor.Pulse(monitorSync);
   }
}

void ImpatientMethod() {
  Action<object> longMethod = LongRunningMethod;
  object monitorSync = new object();
  bool timedOut;
  lock (monitorSync) {
    longMethod.BeginInvoke(monitorSync, null, null);
    timedOut = !Monitor.Wait(monitorSync, TimeSpan.FromSeconds(30)); // waiting 30 secs
  }
  if (timedOut) {
    // it timed out.
  }
}

   ...

これは、C#を使用することの2つの最も楽しい部分を組み合わせたものです。まず、メソッドを非同期的に呼び出すには、ファンシーパンツ BeginInvoke マジックを持つデリゲートを使用します。

次に、モニターを使用して LongRunningMethod から ImpatientMethod にメッセージを送信し、完了したとき、またはメッセージが聞こえない場合に通知します一定の時間で、あきらめます。

(p.s。-これが本当の答えだと冗談を言う。猫の皮を剥ぐ方法は2 ^ 9303あることを知っている。特に.Netで)

他のヒント

メソッドを変更しない限り、それはできません。

2つの方法があります:

  1. このメソッドは、それ自体が実行されている時間を測定し、あるしきい値を超えると途中で返されるように構築されています。
  2. このメソッドは、「この変数が設定されたら終了してください」という変数/イベントを監視し、最初のメソッドで費やされた時間を別のスレッドで測定してから設定するように構築されています経過時間が一定のしきい値を超えたときにその変数。

ここで得られる最も明白な、しかし残念なことに間違った答えは、「スレッドでメソッドを実行し、実行時間が長すぎる場合にThread.Abortを使用するだけです」

唯一の正しい方法は、メソッドが非常に長く実行されたときにクリーンな出口を実行するような方法で協力することです。

別のスレッドでメソッドを実行する3番目の方法もありますが、終了するのを待った後、それを行うのに時間がかかりすぎるので、単に「私はそれを待つつもりはありません」と言う終了しますが、単に破棄します」。この場合、メソッドは引き続き実行され、最終的に終了しますが、それを待っていた他のスレッドは単に放棄します。

誰かに電話をかけて、その本を探して家を検索するように頼むという3番目の方法を考えてください。電話の終わりを5分間待った後、「aw、chuck it」と言うだけで、電話を切る。最終的に他の人が本を見つけて電話に戻りますが、結果が気にならないことに気付くだけです。

MojoFilterの回答は素晴らしい&quot; LongMethod&quot;がリークした場合、凍結します。結果に興味がなくなったら、操作を中止する必要があります。

public void LongMethod()
{
    //do stuff
}

public void ImpatientMethod()
{
    Action longMethod = LongMethod; //use Func if you need a return value

    ManualResetEvent mre = new ManualResetEvent(false);

    Thread actionThread = new Thread(new ThreadStart(() =>
    {
        var iar = longMethod.BeginInvoke(null, null);
        longMethod.EndInvoke(iar); //always call endinvoke
        mre.Set();
    }));

    actionThread.Start();
    mre.WaitOne(30000); // waiting 30 secs (or less)
    if (actionThread.IsAlive) actionThread.Abort();
}

これは古い質問ですが、今では利用できなかった簡単な解決策があります:タスク!

サンプルコードは次のとおりです。

var task = Task.Run(() => LongRunningMethod());//you can pass parameters to the method as well
if (task.Wait(TimeSpan.FromSeconds(30)))
    return task.Result; //the method returns elegantly
else
    throw new TimeoutException();//the method timed-out

C#では、デバッガーまたはOSがアプリが「ハング」していると判断しない限り、メソッドにタイムアウトはありません。それでも処理は続行され、アプリケーションを強制終了しない限り、応答が返され、アプリケーションは引き続き動作します。

データベースへの呼び出しはタイムアウトする可能性があります。

非同期メソッドを作成して、継続できるようにします「忙しい」間、他のものメソッドが完了しますか?

私は定期的にアプリを書いており、プラットフォーム間でタイムクリティカルなタスクを同期する必要があります。 thread.abortを回避できる場合は、すべきです。 http://をご覧ください。 blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx および http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation いつのガイドラインについてthread.abortが適切です。私が実装する概念は次のとおりです。

  • 選択的実行:妥当な成功の可能性が存在する場合にのみ実行します(タイムアウトを満たす能力または他のキュー項目に対する成功の可能性に基づきます)。コードをセグメントに分割し、タスクチャンク間の予想される時間を大まかに知っている場合、それ以上の処理をスキップする必要があるかどうかを予測できます。合計時間は、時間の計算のためにオブジェクトビンタスクを再帰関数でラップするか、予想される待機時間を知るためにワーカーを監視するコントローラークラスを持つことで測定できます。
  • 選択的孤立:合理的な成功の機会が存在する場合にのみ、返品を待ちます。インデックス付きタスクは管理キューで実行されます。タイムアウトを超えたタスクまたは他のタイムアウトを引き起こすリスクは孤立し、代わりにnullレコードが返されます。実行時間の長いタスクは、非同期呼び出しでラップできます。非同期呼び出しラッパーの例を参照してください: http://www.vbusers.com/codecsharp /codeget.asp?ThreadID=67&PostID=1
  • 条件付き選択:選択的実行に似ていますが、個々のタスクではなくグループに基づいています。多くのタスクが相互接続されているため、1つの成功または失敗により追加の処理が無関係になる場合は、実行を開始する前と、長時間実行されるサブタスクを開始する前にチェックするフラグを作成します。これは、parallel.forまたはその他のキューに入れられた同時実行タスクを使用している場合に特に便利です。
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top