我的目标是避免使用线程池线程进行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);
}
}
}
答案 0 :(得分:2)
这是一个满足您需求的基本队列:
//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"));
答案 1 :(得分:1)
您的线程可以在Enqueue作业
之前终止lock (Jobs)
{
if (!ResizeJobs.Any())
{
Interlocked.Decrement(ref threadCount);
return;
}
}
此后,另一份工作将执行 Jobs.Enqueue(作业);
我认为您不需要终止工作线程。它应该等待睡眠状态下的工作