2013-09-25 89 views
0

我寫了我的自定義的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); 
    } 

PROGRAMM的輸出:

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

由於稱爲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); 
} 
相關問題