c# - 在以排队方式执行 cpu 绑定(bind)作业时避免线程池饥饿的策略

标签 c# .net asp.net-mvc multithreading thread-safety

我的目标是避免将线程池线程用于 CPU 密集型工作,从而避免 IIS 停止响应新请求的情况。

你能看到下面的代码有什么问题吗? 这是一种安全/干净的方法吗?你能提供任何改进吗?

    private static ConcurrentQueue<Job> Jobs = new ConcurrentQueue<Job>();
    static int threadCount = 0;

    private void QueueJob(Job job)
    {

        lock(Jobs)
        {
            Jobs.Enqueue(job);
            if (threadCount == 0)
            {

                Interlocked.Increment(ref threadCount); 
                var t= new Thread(new ThreadStart(ConsumeQueue));              
                t.Start();

            }
        }



    }
    private void ConsumeQueue()
    {
        while (true)
        {
            lock (Jobs)
            { 
                if (!Jobs.Any())
                {
                    Interlocked.Decrement(ref threadCount);
                    return;
                }
            }

            Job j;

            var jobToDo = Jobs.TryDequeue(out j);

            if (jobToDo)
            {
                DoCPUBoundWork(j);
            }
        }

    }

最佳答案

这是一个应该满足您需求的基本队列:

//sealed so we don't have to implement full IDisposable pattern
sealed class Q:IDisposable
{
    private CancellationTokenSource cts = new CancellationTokenSource();
    private BlockingCollection<Action> queue =
        new BlockingCollection<Action>(new ConcurrentQueue<Action>());

    public Q()
    {
        new Thread(() => RunQueue()).Start();
    }

    private void RunQueue()
    {
        while(!cts.IsCancellationRequested)
        {
            Action action;
            try
            {
                //lovely... blocks until something is available
                //so we don't need to deal with messy synchronization
                action = queue.Take(cts.Token); 
            }
            catch(OperationCanceledException)
            {
                break;
            }
            action();
        }
    }

    public void AddJob(Action action)
    {
        try
        {
            queue.Add(action,cts.Token);
        }
        catch(OperationCanceledException e)
        {
            throw new ObjectDisposedException("Q is disposed",e);
        }
    }

    public void Dispose()
    {
        if(!cts.IsCancellationRequested)
        {
            cts.Cancel();
        }
    }
}

按如下方式使用:
Q actionQueue=new Q();
actionQueue.AddJob(() => Console.WriteLine("action1"));
actionQueue.AddJob(() => Console.WriteLine("action2"));
actionQueue.AddJob(() => Console.WriteLine("action3"));

关于c# - 在以排队方式执行 cpu 绑定(bind)作业时避免线程池饥饿的策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13821254/

相关文章:

asp.net-mvc - Kigg MVC 应用程序是否干燥?我们可以调整存储库吗

c# - 从 Javascript 访问 MVC 的模型属性

c# - Entity Framework ,获取选中项的周边项

c# - 如何制作 ToolStripComboBox 来填充 ToolStrip 上的所有可用空间?

.net - WCF:公开未设置的只读 DataMember 属性?

c# - 如何获得与时区无关的时间

c# - JsonResult 有时会被截断

c# - SQLConnection 使用随机命名管道而不是 tcp

c# - 在 .Net 3.5 中使用 GetDirectories() 识别错误的 ReparsePoints?

c# - 通过网络服务在客户中引发事件