3

再度呼び出す前に終了する必要があるビジネス ロジック メソッドがあります。複数のクライアントが一度に呼び出すことができます。

public void DoSomething() {}

メソッドをプライベートにして、リクエストをキューに入れる新しいパブリックメソッドを作成することで解決することを考えていました。

public void QueueSomeWork()
{
    // put on a Queue object
    // How will DoSomething get invoked now?
}

private void DoSomething() {}

私はこの問題をエレガントな方法で解決しようとしています。私の問題はDoSomething()、実行する方法を知る方法です。キューをチェックするタイマーを作成することも考えましたが、1 年に 2 回程度発生する何かのために 24 時間 365 日稼働することになります。

もう 1 つの考えは、DoSomething()他の何かがサブスクライブするイベントを発生させ、キューからいくつかの作業を取り出し、 を呼び出すことDoSomething()です。より良い方法はありますか?

4

5 に答える 5

10

ロックガードを使ってみませんか?

例:

   private static Object lockGuard = new Object();
   public void DoSomething()
   {
     lock (lockGuard) 
      {
          //logic gere
      }
    }

リソースをロックすると、複数のスレッドから同時にアクセスできなくなります。

ロックの詳細: http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.110).aspx

于 2013-06-07T20:33:46.550 に答える
3

数値がそれほど高くない場合 (DoSomething内部でリソースがどのように消費されるかによって異なります)。私はこれで行きます:

public static async void QueueSomeWork()
{
    await Task.Run(() => { DoSomething(); });
}

static readonly object lockObject = new object();
static void DoSomething()
{
    lock (lockObject)
    {
        // implementation
    }
}

数値がこれより高い場合は、キューに入れられるタスクの数に制限を設ける必要があります。

static long numberOfQueuedTasks = 0;
const long MAX_TASKS = 10000; // it depends how DoSomething internals consume resource
public static async void QueueSomeWork()
{
    if (numberOfQueuedTasks > MAX_TASKS)
    {
        var wait = new SpinWait();

        while (numberOfQueuedTasks > MAX_TASKS) wait.SpinOnce();
    }

    await Task.Run(() => { Interlocked.Increment(ref numberOfQueuedTasks); DoSomething(); });
}

static readonly object lockObject = new object();
static void DoSomething()
{
    try
    {
        lock (lockObject)
        {
            // implementation
        }
    }
    finally
    {
        Interlocked.Decrement(ref numberOfQueuedTasks);
    }
}
于 2013-06-07T20:53:04.510 に答える
2

これを行う簡単な方法は、Java のキーワードにMethodImplOptions.Synchronized似た機能を持つ でメソッドを装飾することです。synchronized

[MethodImpl(MethodImplOptions.Synchronized)]
private void DoSomething()
{
    // ...
}

主な欠点は、これにより現在のインスタンスがロックされることです。これにより、他の場所で既にロックを使用している場合、デッドロックが発生する可能性があります。

于 2013-06-07T20:52:54.577 に答える
0

これがコードのみの問題である場合は、ロック ソリューションが適切です。しかし、一連のオブジェクト (レコード) を干渉なしで変更する必要がある DB トランザクションを実行することがあります。良い例は、DB レコードのシーケンス列挙を再実行する場合です。DB にロック テーブルを作成し、特定の定義済みレコードをロックして、トランザクションで最初に更新することができます。これにより、アプリケーションによって (同じコード領域で) 作成された他のトランザクションが、更新するテーブルに到達することさえできなくなります。2 番目の呼び出しは、最初の呼び出しが完了した後にのみ続行されます。ただのヒント。

于 2013-06-07T20:52:29.480 に答える
0

ここにアイデアがあります。おそらくそれを使用するときにロックしたいでしょうdoSomethingCountが、DoSomething をキューに入れて続行することに関しては、別のスレッドで実行されるため、これが機能する可能性があります。キューに問題がなかったので、発火して忘れて、実際に発信者をブロックする必要はないと思います。

    // This will increment the count and kick off the process of going through
    // the calls if it isn't already running. When it is done, it nulls out the task again
    // to be recreated when something is queued again.
    public static void QueueSomething()
    {
        doSomethingCount++;
        if (doSomethingTask == null)
        {
            doSomethingTask =
                Task.Run((Action)(() =>
                {
                    while (doSomethingCount > 0)
                    {
                        DoSomething();
                        doSomethingCount--;
                    }
                }))
                .ContinueWith(t => doSomethingTask = null);
        }
    }

    // I just put something in here that would take time and have a measurable result.
    private static void DoSomething()
    {
        Thread.Sleep(50);
        thingsDone++;
    }

    // These two guys are the data members needed.
    private static int doSomethingCount = 0;
    private static Task doSomethingTask;

    // This code is just to prove that it works the way I expected. You can use it too.
    public static void Run()
    {
        for (int i = 0; i < 10; i++)
        {
            QueueSomething();
        }

        while (thingsDone < 10)
        {
            Thread.Sleep(100);
        }

        thingsDone = 0;
        QueueSomething();

        while (thingsDone < 1)
        {
            Thread.Sleep(100);
        }

        Console.WriteLine("Done");
    }

    // This data point is just so I could test it. Leaving it in so you can prove it yourself.
    private static int thingsDone = 0;
于 2013-06-07T20:45:26.040 に答える