33

サービスとして使用するコントローラーとアクションを作成しました。このサービスは、かなりコストのかかるアクションを実行します。現在実行中のアクションが既にある場合、このアクションへのアクセスを制限したいと思います。

asp.net mvcアクションをロックする組み込みの方法はありますか?

ありがとう

4

6 に答える 6

62

このようなものをお探しですか?

public MyController : Controller
{
    private static object Lock = new object();

    public ActionResult MyAction()
    {
        lock (Lock)
        {
            // do your costly action here
        }    
    }
}

上記は、スレッドが現在lockブロック内のコードを処理している場合、他のスレッドがアクションを実行するのを防ぎます。

更新:これがどのように機能するかです

メソッド コードは常にスレッドによって実行されます。負荷の高いサーバーでは、2 つ以上の異なるスレッドがメソッドに入って並行して実行を開始する可能性があります。質問によると、これはあなたが防ぎたいことです。

private Lockオブジェクトが であることに注意してくださいstatic。これは、コントローラーのすべてのインスタンスで共有されることを意味します。したがって、ヒープ上に構築されたこのコントローラーのインスタンスが 2 つある場合でも、それらの両方が同じ Lock オブジェクトを共有します。(オブジェクトに Lock という名前を付ける必要はありません。Jerry または Samantha という名前を付けても、同じ目的を果たすことができます。)

これが何が起こるかです。プロセッサは、一度に 1 つのスレッドしかコードのセクションに入ることを許可できません。通常の状況では、スレッド A がコード ブロックの実行を開始し、次にスレッド B がその実行を開始する可能性があります。したがって、理論的には、2 つのスレッドで同じメソッド (または任意のコード ブロック) を同時に実行できます。

これlockを防ぐためにキーワードを使用できます。lockスレッドがセクションにラップされたコードのブロックに入ると、ロック オブジェクト (フィールドとしてマークする必要があるlockキーワード、別名、、、LockまたはJerryの後の括弧内にあるもの) を「取得」します。ロックされたセクションが実行されている間、ロック オブジェクトを「保持」します。スレッドがロックされたセクションを出ると、ロック オブジェクトを「放棄」します。スレッドがロック オブジェクトを取得してからロック オブジェクトを放棄するまで、他のすべてのスレッドはコードのロックされたセクションに入ることができません。実際には、現在実行中のスレッドがロック オブジェクトを放棄するまで「一時停止」されます。Samanthastatic

したがって、スレッド A は MyAction メソッドの先頭でロック オブジェクトを取得します。ロック オブジェクトを放棄する前に、スレッド B もこのメソッドを実行しようとします。ただし、ロック オブジェクトはスレッド A によって既に保持されているため、取得できません。そのため、スレッド A がロック オブジェクトを放棄するのを待ちます。完了すると、スレッド B はロック オブジェクトを取得し、コード ブロックの実行を開始します。スレッド B がブロックの実行を終了すると、このメソッドの処理を委任された次のスレッドのためにロック オブジェクトを放棄します。

...しかし、これがあなたが探しているものかどうかはわかりません...

このアプローチを使用しても、必ずしもコードの実行が速くなるとは限りません。一度に 1 つのスレッドだけがコードのブロックを実行できるようにするだけです。通常、パフォーマンス上の理由ではなく、並行性の理由で使用されます。質問で特定の問題についてより多くの情報を提供できる場合は、これよりも良い答えがあるかもしれません.

上記のコードは、ブロックを実行する前に他のスレッドを待機させることに注意してください。これがあなたが望むものではなく、別のスレッドによってすでに実行されている場合はアクション全体を「スキップ」したい場合は、Oshryの回答に似たものを使用してください。この情報は、キャッシュ、セッション、またはその他のデータ ストレージ メカニズムに保存できます。

于 2012-12-16T14:52:28.520 に答える
7

非同期操作をサポートしているため、SemaphoreSlimを使用することを好みます。

読み取り/書き込みを制御する必要がある場合は、ReaderWriterLockSlimを使用できます。

次のコード スニップでは、 を使用していSemaphoreSlimます。

public class DemoController : Controller
{
    private static readonly SemaphoreSlim ProtectedActionSemaphore =
        new SemaphoreSlim(1);

    [HttpGet("paction")] //--or post, put, delete...
    public IActionResult ProtectedAction()
    {
        ProtectedActionSemaphore.Wait();
        try
        {
            //--call your protected action here
        }
        finally
        {
            ProtectedActionSemaphore.Release();
        }

        return Ok(); //--or any other response
    }

    [HttpGet("paction2")] //--or post, put, delete...
    public async Task<IActionResult> ProtectedActionAsync()
    {
        await ProtectedActionSemaphore.WaitAsync();
        try
        {
            //--call your protected action here
        }
        finally
        {
            ProtectedActionSemaphore.Release();
        }

        return Ok(); //--or any other response
    }
}

お役に立てば幸いです。

于 2019-10-17T23:07:15.793 に答える
2

要件に応じてカスタム属性を作成し、[UseLock]アクションの前に配置できます

于 2012-12-16T11:55:47.403 に答える
-3

これを行う最も簡単な方法は、アクションが必要な BL を既に実行していることを示すブール値をキャッシュに保存することです。

if (System.Web.HttpContext.Current.Cache["IsProcessRunning"])
{
    System.Web.HttpContext.Current.Cache["IsProcessRunning"] = true;
    // run your logic here
    System.Web.HttpContext.Current.Cache["IsProcessRunning"] = false
}

もちろん、属性としてこれまたは同様のことを行うこともできます。

于 2012-12-16T12:18:09.283 に答える