如何将方法限制为n个并发调用

时间:2012-12-14 14:17:51

标签: c# multithreading .net-4.0 concurrency

我有一个集成服务,它运行计算繁重的数据绑定过程。我想确保在这些进程中运行的n = 5,n = 5(但是n将是可配置的,在运行时可更改的)。我们的想法是将服务器上的负载限制在安全水平。该方法处理的数据量受批量限制,因此我不需要担心1个进程代表比另一个更大的负载。

处理方法由另一个进程调用,其中运行工资单的请求保存在队列中,我可以在该点插入一些逻辑以确定是立即处理此请求,还是将其留在队列中。

所以我想在与处理方法相同的服务上使用一个单独的方法,它可以告诉我服务器是否可以接受对处理方法的另一个调用。它会问,“有多少工资单正在运行?是不是n?”什么是实现这一目标的巧妙方法?

----------- ------------编辑

我认为我需要说清楚,决定是否将请求从队列中取出的过程与从WCF边界处理工资核算数据的服务分开。停止工资单处理过程中的一个线程不会阻止更多的请求进入

4 个答案:

答案 0 :(得分:4)

您可以使用Semaphore执行此操作。

public class Foo
{
    private Semaphore semaphore;
    public Foo(int numConcurrentCalls)
    {
        semaphore = new Semaphore(numConcurrentCalls, numConcurrentCalls);
    }

    public bool isReady()
    {
        return semaphore.WaitOne(0);
    }

    public void Bar()
    {
        try
        {
            semaphore.WaitOne();//it will only get past this line if there are less than 
            //"numConcurrentCalls" threads in this method currently.
            //do stuff
        }
        finally
        {
            semaphore.Release();
        }
    }
}

答案 1 :(得分:1)

查看Object Pool模式。这就是你所描述的。虽然模式不是严格要求,但您可以公开池中当前对象的数量,最大(已配置)数字,高水位等。

答案 2 :(得分:0)

我认为你可能想要一个BlockingCollection,其中集合中的每个项目代表一个并发调用。

另见IProducerConsumerCollection

如果您只是使用线程,我建议您查看限制线程并发的方法(例如TaskScheduler.MaximumConcurrencyLevel属性和this example。)。

另见ParallelEnumerable.WithDegreeOfParallelism

答案 3 :(得分:0)

void ThreadTest()
{
    ConcurrentQueue<int> q = new ConcurrentQueue<int>();
    int MaxCount = 5;
    Random r = new Random();

    for (int i = 0; i <= 10000; i++)
    {
        q.Enqueue(r.Next(100000, 200000));
    }

    ThreadStart proc = null;
    proc = () =>
    {
        int read = 0;
        if (q.TryDequeue(out read))
        {
            Console.WriteLine(String.Format("[{1:HH:mm:ss}.{1:fff}] starting: {0}... @Thread {2}", read, DateTime.Now, Thread.CurrentThread.ManagedThreadId));
            Thread.Sleep(r.Next(100, 1000));
            Console.WriteLine(String.Format("[{1:HH:mm:ss}.{1:fff}] {0} ended! @Thread {2}", read, DateTime.Now, Thread.CurrentThread.ManagedThreadId));
            proc();
        }
    };

    for (int i = 0; i <= MaxCount; i++)
    {
        new Thread(proc).Start();
    }
}