現在、既存のアプリケーションに Web サービス ベースのフロント エンドを作成しています。そのために、私はWCF LOB Adapter SDKを使用しています。これにより、外部データと操作を Web サービスとして公開するカスタム WCF バインディングを作成できます。
SDK は実装するいくつかのインターフェイスを提供し、それらのメソッドの一部は時間制限があります。実装は、指定された時間内に作業を完了するか、TimeoutExceptionをスローすることが期待されます。
調査の結果、「Implement C# Generic Timeout」という質問にたどり着きました。この質問は、ワーカー スレッドを使用することを賢明にアドバイスしています。その知識があれば、次のように書くことができます。
public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex,
int maxChildNodes, TimeSpan timeout)
{
Func<MetadataRetrievalNode[]> work = () => {
// Return computed metadata...
};
IAsyncResult result = work.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeout)) {
return work.EndInvoke(result);
} else {
throw new TimeoutException();
}
}
ただし、ワーカー スレッドがタイムアウトした場合にどうするかについては、コンセンサスが明確ではありません。上記のコードのように忘れるか、中止することができます:
public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex,
int maxChildNodes, TimeSpan timeout)
{
Thread workerThread = null;
Func<MetadataRetrievalNode[]> work = () => {
workerThread = Thread.CurrentThread;
// Return computed metadata...
};
IAsyncResult result = work.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeout)) {
return work.EndInvoke(result);
} else {
workerThread.Abort();
throw new TimeoutException();
}
}
現在、スレッドを中止することは、広く間違っていると考えられています。進行中の作業を中断し、リソースをリークし、ロックを台無しにし、スレッドが実際に実行を停止することさえ保証しません。つまり、HttpResponse.Redirect()
呼び出されるたびにスレッドを中止し、IIS はそれに完全に満足しているようです。何らかの形で対処する準備ができているのかもしれません。私の外部アプリケーションはおそらくそうではありません。
一方、リソース競合の増加 (プール内の使用可能なスレッドの減少) は別として、ワーカー スレッドにそのコースを実行させた場合、work.EndInvoke()
呼び出されることはないため、とにかくメモリ リークは発生しませんか? より具体的には、MetadataRetrievalNode[]
によって返された配列はwork
永遠に残りませんか?
これは 2 つの悪のうち小さい方を選択するだけの問題ですか、それともワーカー スレッドを中止せずに使用されたメモリを再利用する方法はありBeginInvoke()
ますか?