2012-11-01 43 views
6

下單和MonoTouch的延遲,我看到一個大約爲500毫秒的延遲,當我打電話之間:Task.Factory.StartNew()在單聲道/ MonoTouch的

StartNew(Action<object> action, object state, CancellationToken cancellationToken, 
    TaskCreationOptions creationOptions, TaskScheduler scheduler); 

與勞動者代碼實際上啓動時執行。

我創建了一個測試,以證明這一點:在Mono下

public static class TestTaskFactory 
{ 
    private class TaskInfo 
    { 
     public int Number; 
    } 

    private static int NUM_TASKS = 5; 
    private static int NumFinished = 0; 

    public static void Run() 
    { 
     for (int n = 1; n <= NUM_TASKS; n++) 
     { 
      Log("Starting task #" + n + " ..."); 
      var task_info = new TaskInfo { Number = n }; 
      var task = Task.Factory.StartNew(Worker, task_info, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); 
      Thread.Sleep(0); 
     } 

     Log("Waiting for tasks to finish ..."); 
     while (NumFinished < NUM_TASKS) 
     { 
      Thread.Sleep(1); 
     } 

     Log("All done"); 
    } 

    private static void Worker(object state) 
    { 
     var task_info = (TaskInfo)state; 
     Log("Task #" + task_info.Number + " running"); 

     // Do something 
     Thread.Sleep(2000); 

     // Done 
     ++NumFinished; 
    } 

    private static void Log(string msg) 
    { 
     Console.WriteLine(DateTime.Now.ToString("HH.mm.ss.fff") + ": Thread " + Thread.CurrentThread.ManagedThreadId + ": " + msg); 
    } 
} 

輸出在Mac上:

16.57.31.420: Thread 1: Starting task #1 ... 
16.57.31.508: Thread 1: Starting task #2 ... 
16.57.31.508: Thread 1: Starting task #3 ... 
16.57.31.508: Thread 1: Starting task #4 ... 
16.57.31.508: Thread 1: Starting task #5 ... 
16.57.31.508: Thread 1: Waiting for tasks to finish ... 
16.57.31.510: Thread 5: Task #1 running 
16.57.32.009: Thread 6: Task #2 running <-- Approx 500 msec later 
16.57.32.511: Thread 7: Task #3 running <-- Approx 500 msec later 
16.57.33.012: Thread 8: Task #4 running <-- Approx 500 msec later 
16.57.33.513: Thread 9: Task #5 running <-- Approx 500 msec later 
16.57.35.515: Thread 1: All done 

這是因爲如果單要等待長達500毫秒之前重用現有的線程使新的一個。如果我將工作時間減少到500毫秒以下,則延遲會減少。例如,改變工人Thread.sleep代碼(2000)到了Thread.Sleep(50):

... 
17.13.20.262: Thread 5: Task #1 running 
17.13.20.314: Thread 5: Task #2 running <-- approx 50 msec later 
17.13.20.365: Thread 5: Task #3 running <-- approx 50 msec later 
17.13.20.416: Thread 5: Task #4 running <-- approx 50 msec later 
17.13.20.466: Thread 5: Task #5 running <-- approx 50 msec later 

但是在MS框架4.0,工人代碼之前沒有延遲開始:

... 
17.05.42.238: Thread 9: Waiting for tasks to finish ... 
17.05.42.256: Thread 11: Task #1 running 
17.05.42.256: Thread 12: Task #3 running <-- little delay 
17.05.42.256: Thread 13: Task #4 running <-- little delay 
17.05.42.257: Thread 10: Task #2 running <-- little delay 
17.05.43.264: Thread 14: Task #5 running <-- little delay 

在我提交Mono錯誤報告之前,我想要明智地檢查一下,我不會錯過Mono或使用Task.Factory時需要做的一些調整。我真的在我的真實應用程序中使用最大併發調度程序。

所以我的問題:這是Mono/MonoTouch中的錯誤嗎?

更新:我已經從使用Mono *下的ThreadPool切換到Ami Bar的智能線程池(github; Code Project article)。 GSerjo的Extended Thread Pool也很好看,但有很多依賴,我試圖避免在手機上。我在Xamarim thread上寫了一些簡單的測試。我可能錯過了100個其他的線程池實現,但到目前爲止我對SmartThreadPool感到滿意。使用WINDOWS_PHONE模式在MonoTouch下編譯。

回答

6

所以我的問題:這是一個單聲道/ MonoTouch的錯誤?

不一定。我懷疑這只是線程池不願意每500ms啓動一個以上的新線程。請注意,您看到第一個任務幾乎立即啓動。只有在那之後你纔會看到延遲。

如果你在.NET 4.5上使用更多的任務,你會看到類似的東西,除了每秒開始的「大塊」線程。

您可能會發現調用ThreadPool.SetMinThreads有幫助,假設在MonoTouch中可用。

+0

是的,SetMinThreads()做到了。 500毫秒的值似乎非常隨意。即使在iOS下,這也是一個超長時間,更不用說Mono for Mac,我也看到了這一點。基於快速谷歌搜索這可能是一個固定的MS框架的特定版本。我會更多地研究/實驗並回報。單聲道默認不適合我。 – t9mike

+0

@ t9mike:是的,我認爲這是.NET 4之前的時機,我相信線程池幾乎完全被重寫。 –

+4

線程池中線程的緩慢啓動是爲了避免線程風暴。 –