我编写了自定义TaskScheduler:
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
private List<Thread> _threads;
private bool work = true;
public LimitedConcurrencyLevelTaskScheduler(int maxConcurrencyLevel)
{
_threads = new List<Thread>();
for (int i = 0; i < maxConcurrencyLevel; i++)
{
_threads.Add(new Thread(() =>
{
while (work)
{
TryExecuteTask(_tasks.Take());
}
}) { IsBackground = true, Name = "TaskShedulerThread#" + i });
}
foreach (var thread in _threads)
{
thread.Start();
}
}
protected override void QueueTask(Task task)
{
_tasks.Add(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return !_threads.Contains(Thread.CurrentThread) && TryExecuteTask(task);
}
public override int MaximumConcurrencyLevel { get { return 1; } }
protected override IEnumerable<Task> GetScheduledTasks()
{
return _tasks.ToArray();
}
public void Dispose()
{
if (_threads != null)
{
_tasks.CompleteAdding();
work = false;
_tasks.Dispose();
_tasks = null;
_threads = null;
}
}
}
以这种方式使用它:
static void Main(string[] args)
{
var taskScheduller = new LimitedConcurrencyLevelTaskScheduler(1);
Thread.CurrentThread.Name = "MainThread";
var taskFactory = new TaskFactory(taskScheduller);
var tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = taskFactory.StartNew(() => Console.WriteLine(String.Format("Call in {0}", Thread.CurrentThread.Name)));
}
Task.WaitAll(tasks);
}
程序的输出:
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in MainThread
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in MainThread
Call in MainThread
Call in MainThread
Call in MainThread
Call in MainThread
Call in MainThread
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
Call in TaskShedulerThread#0
...
为什么我的任务在主线程中运行?
答案 0 :(得分:0)
由于名为task inlining的TPL功能,任务正在主线程上执行。当一个线程在尚未开始执行的任务上调用WaitAll
(或任何类似的方法)时,TPL可以允许所述线程尝试执行挂起的任务本身,而不是阻塞直到它被其中一个执行任务调度程序的工作线程。
可以通过覆盖任务调度程序的TryExecuteTaskInline
方法来控制此行为,禁止它执行任何任务,除非当前线程恰好是工作线程。
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return !_threads.Contains(Thread.CurrentThread) && TryExecuteTask(task);
}
在您的实施中,您只需要在Contains
检查之前删除否定:
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return _threads.Contains(Thread.CurrentThread) && TryExecuteTask(task);
}