0

私はスレッド化を学んでいます.私の意図は、計算のためにいくつかの値をメソッドに渡すことです,結果が20ミリ秒以内に返されない場合,私は「操作タイムアウト」を報告します.私の理解に基づいて、私は次のようにコードを実装しました:

public delegate long CalcHandler(int a, int b, int c);


public static void ReportTimeout()
    {
        CalcHandler doCalculation = Calculate;

        IAsyncResult asyncResult = 
        doCalculation.BeginInvoke(10,20,30, null, null);

        if (!asyncResult.AsyncWaitHandle.WaitOne(20, false))
        {
            Console.WriteLine("..Operation Timeout...");
        }

        else
       {
        // Obtain the completion data for the asynchronous method.
        long val;
        try
        {
            val=  doCalculation.EndInvoke(asyncResult);
            Console.WriteLine("Calculated Value={0}", val);
        }
        catch
        {
            // Catch the exception
        }
     }

    } 

public static long Calculate(int a,int b,int c)
     {
        int m;
        //for testing timeout,sleep is introduced here.
        Thread.Sleep(200);
        m = a * b * c;
        return m;
    }

質問:

(1) timeout を報告する適切な方法ですか?

(2) 時間切れの場合は EndInvoke() を呼び出しません。そのような場合、EndInvoke() の呼び出しは必須ですか?

(3) 私はそれを聞いた

「非同期メソッドの戻り値を処理したくない場合でも、EndInvoke を呼び出す必要があります。そうしないと、BeginInvoke を使用して非同期呼び出しを開始するたびにメモリ リークが発生する危険があります」

メモリに関連するリスクは何ですか? 例を挙げることができますか?

4

2 に答える 2

2

回答

(1) 通常は System.TimeoutException をスローするだけです

(2) EndInvoke() が必要な理由は、戻り値 (またはスローされた例外) にメモリ割り当てがある場合、GC がそれをすぐにクリーンアップできない可能性があるためです。これが大きな問題になったケースは見たことがありません...しかし、それは私だけです。

本当に心配なら、ThreadPool.QueueUserWorkItem を呼び出すことができます。これは、ほとんどの場合、上記の非同期呼び出しが行うことです。(注: WinForms またはその他のスレッド依存のコンテキストで問題になる可能性があります)。とにかく、次のように独自のワークアイテムを実行できます。

    public static long Calc(CalcHandler fn, int a, int b, int c)
    {
        return Run<long>(TimeSpan.FromSeconds(20), delegate { return fn(a, b, c); });
    }

    public static T Run<T>(TimeSpan timeout, Func<T> operation)
    {
        Exception error = null;
        T result = default(T);

        ManualResetEvent mre = new ManualResetEvent(false);
        System.Threading.ThreadPool.QueueUserWorkItem(
            delegate(object ignore)
            {
                try { result = operation(); }
                catch (Exception e) { error = e; }
                finally { mre.Set(); }
            }
        );
        if (!mre.WaitOne(timeout, true))
            throw new TimeoutException();
        if (error != null)
            throw new TargetInvocationException(error);
        return result;
    }
于 2009-10-08T22:04:17.573 に答える
1

タイムアウト値から、はい、これはあなたが期待するようにタイムアウトを設定しようとしています。

記憶のリスクについて。EndInvokeを呼び出さないと、デリゲートへの参照が残っている可能性があり、使用されているリソースは、アプリケーションが終了するまでガベージコレクションされない可能性があります。正確な実装は、私が見つけたものから100%文書化されていませんが、ANTSProfilerなどのツールで確認できます。

ここに役立つディスカッションがあります。

于 2009-10-08T21:50:06.050 に答える